AtomicInteger.incrementAndGet() против AtomicInteger.getAndIncrement()

Если возвращаемое значение не представляет интереса, есть ли какая-либо (даже нерелевантная на практике) разница между AtomicInteger.getAndIncrement() и AtomicInteger.incrementAndGet(), когда возвращаемое значение игнорируется?

Я думаю о различиях, например, о том, что было бы более идиоматично, а также о том, что будет меньше нагружать кэши ЦП при синхронизации, или что-то еще, что-нибудь, что поможет решить, какой из них использовать более рационально, чем подбрасывание монеты.


person hyde    schedule 28.02.2013    source источник
comment
если возвращаемое значение представляет интерес, возможно ли, что в случае AtomicInteger.getAndIncrement() два потока получат одно и то же значение?   -  person Faiz Halde    schedule 18.07.2018
comment
@FaizHalde: это нужно было задать отдельным вопросом. Но нет, если ничто не уменьшает атомарное целое число (и оно не переполняется), то никакие два вызова не будут наблюдать одно и то же значение от вызова getAndIncrement.   -  person Joachim Sauer    schedule 31.08.2020


Ответы (5)


Поскольку ответа на фактический вопрос не было дано, вот мое личное мнение, основанное на других ответах (спасибо, проголосовавших) и соглашении Java:

incrementAndGet()

лучше, потому что имена методов должны начинаться с глагола, описывающего действие, а предполагаемое действие здесь — только увеличение.

Начало с глагола является общим соглашением Java, также описанным в официальных документах:

"Методы должны быть глаголами в смешанном регистре с первой буквой в нижнем регистре, с заглавной первой буквой каждого внутреннего слова."

person hyde    schedule 01.03.2013
comment
Было бы неплохо, если бы они представили простой метод increment() просто для удобочитаемости. - person Bennett Lynch; 31.01.2018

Код по сути тот же, поэтому это не имеет значения:

public final int getAndIncrement() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return current;
    }
}

public final int incrementAndGet() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return next;
    }
}
person assylias    schedule 28.02.2013
comment
@irreputable Не уверен, что понимаю вашу точку зрения - если вы не сохраните возвращаемое значение, var.incrementAndGet(); и var.getAndIncrement(); дадут точно такой же результат... - person assylias; 28.02.2013
comment
да. Я говорю, что на самом деле одного из методов достаточно, другой как бы избыточен. - person irreputable; 28.02.2013
comment
@irreputable Ах, извините... Да. Также я не уверен, почему incrementAndGet просто не вызывает addAndGet(1) вместо того, чтобы в основном дублировать код... - person assylias; 28.02.2013
comment
Дуг Ли одержим каждым циклом процессора :) - person irreputable; 28.02.2013
comment
@irreputable Дополнение к этому вопросу в этом вопросе. - person assylias; 28.02.2013

Нет, нет никакой разницы (если вас не волнует возвращаемое значение).

Код этих методов (в OpenJDK) отличается только тем, что один использует return next, а другой использует return current.

Оба используют compareAndSet под капотом с одним и тем же алгоритмом. Оба должны знать как старое, так и новое значение.

person Joachim Sauer    schedule 28.02.2013

Просто хочу добавить к существующим ответам: может быть очень небольшая незаметная разница.

Если вы посмотрите на эта реализация:

public final int getAndIncrement() {
    return unsafe.getAndAddInt(this, valueOffset, 1);
}

public final int incrementAndGet() {
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}

Обратите внимание: обе функции вызывают одну и ту же функцию getAndAddInt, за исключением части +1, а это значит, что в этой реализации getAndIncrement работает быстрее.

Но вот старая реализация:

public final int getAndIncrement() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return current;
    }
}

public final int incrementAndGet() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return next;
    }
}

Единственная разница — это возвращаемая переменная, поэтому обе функции работают одинаково.

person Iłya Bursov    schedule 30.08.2017

Вот я привожу пример. Надеюсь, это рассеет ваши сомнения.

Предположим, у меня есть переменная i как

AtomicInteger i = new AtomicInteger();

В этом случае:

i.getAndIncrement() ‹==> i++;

А также

i.incrementAndGet() ‹==> ++i;

Пожалуйста, взгляните на следующие программы

public class Test1
{   
    public static void main(String[] args) 
    {               
        AtomicInteger i = new AtomicInteger();
        System.out.println(i.incrementAndGet());  
        System.out.println(i);  

    }

}

**выход

1 1 ======================================**

public class Test2
{   
    public static void main(String[] args) 
    {               
        AtomicInteger i = new AtomicInteger();
        System.out.println(i.getAndIncrement());  
        System.out.println(i); 

    }

}

**выход

0 1 -------------**

Комментарий: 1) В классе Test1 функция incrementAndGet() сначала увеличивает значение i, а затем печатает.

2) В классе Test2 функция getAndIncrement() сначала напечатает значение i, а затем увеличит его.

Это все.

person Ajju_bhai    schedule 02.06.2017
comment
Спасибо за Ваш ответ. Однако в вашем ответе фактически используется (распечатывается) результат. Вопрос касается ситуации, когда когда возвращаемое значение не представляет интереса... - person hyde; 05.06.2017