AtomicInteger.incrementAndGet() frente a AtomicInteger.getAndIncrement()

5 minutos de lectura

Cuando el valor de retorno no es de interés, ¿hay alguna diferencia (incluso irrelevante en la práctica) entre AtomicInteger.getAndIncrement() y AtomicInteger.incrementAndGet() métodos, cuando se ignora el valor de retorno?

Estoy pensando en diferencias como cuál sería más idiomático, así como cuál pondría menos carga en las memorias caché de la CPU sincronizadas, o cualquier otra cosa realmente, cualquier cosa que ayude a decidir cuál usar de manera más racional que lanzar una moneda.

  • si el valor de retorno es de interés, ¿es posible que en el caso de AtomicInteger.getAndIncrement() dos hilos obtendrán el mismo valor?

    – ffff

    18 de julio de 2018 a las 12:42

  • @FaizHalde: eso debería haberse preguntado en una pregunta separada. Pero no, si nada disminuye el entero atómico (y no se desborda), entonces dos llamadas no observarán el mismo valor al llamar getAndIncrement.

    – Joaquín Sauer

    31 de agosto de 2020 a las 8:19

  • @FaizHalde si 2 o más subprocesos están en disputa, “anterior” o en este caso “actual” será lo mismo … pero después de un compareAndSet() solo uno hilo (el ganador) volverá. Este ganador devolverá la versión que coincidió con la versión que vio el hilo al comienzo del giro.

    – Delark

    25 de febrero de 2022 a las 19:55

  • @FaizHalde … Todos los subprocesos que aún están compitiendo fallarán en su comapreAndSet() porque la versión del valor atómico ya no coincidirá con la que vieron cuando la primera .get() al comienzo de sus respectivos spin-locks se hizo, por lo que volverán a intentarlo, en su próximo giro su “actual” finalmente reflejará el cambio, por lo que la respuesta es: No, AtomicInteger.getAndIncrement() nunca traerá el mismo valor, incluso bajo una fuerte disputa.

    – Delark

    25 de febrero de 2022 a las 19:58


Como no se ha dado ninguna respuesta a la pregunta real, aquí está mi opinión personal basada en las otras respuestas (gracias, votado a favor) y la convención de Java:

incrementAndGet()

es mejor, porque los nombres de los métodos deben comenzar con el verbo que describe la acción, y la acción prevista aquí es solo incrementar.

Comenzar con verbo es la convención común de Java, también descrita por documentos oficiales:

“Los métodos deben ser verbos, en caso mixto con la primera letra en minúscula, con la primera letra de cada palabra interna en mayúscula”.

  • Sería bueno que expusieran un simple increment() método, sólo por el bien de la legibilidad.

    – Bennett Lynch

    31 de enero de 2018 a las 0:22

  • Supongo que la razón por la que lo mantuvieron así en atomicInteger() es para “mantener la convención”, ya que el comportamiento de devolver “anterior” o “siguiente” se convierte en una necesidad cuando se trata de intercambios atómicos. Esto no es útil en números enteros ya que el siguiente siempre será prev + 1 (y prev == next -1), pero cuando se trata de objetos es extremadamente útil. Más problemático para mí es el hecho de que un compareAndSet fallido no te da un testigo.

    – Delark

    25 de febrero de 2022 a las 20:11

El código es esencialmente el mismo, así que no importa:

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;
    }
}

  • incrementAndGet()==getAndIncrement()+1

    – irreputable

    28 de febrero de 2013 a las 17:24

  • @irreputable No estoy seguro de entender su punto: si no almacena el valor devuelto, var.incrementAndGet(); y var.getAndIncrement(); producir exactamente el mismo resultado…

    – asilias

    28 de febrero de 2013 a las 17:28

  • Sí. Estoy diciendo que en realidad uno de los métodos es suficiente, el otro es un poco redundante.

    – irreputable

    28/02/2013 a las 17:30

  • @irreputable Ah, lo siento… Sí. Además, no estoy seguro de por qué. incrementAndGet no llama simplemente addAndGet(1) en lugar de duplicar principalmente el código…

    – asilias

    28 de febrero de 2013 a las 17:32

  • Doug Lea está obsesionado con cada ciclo de CPU 🙂

    – irreputable

    28 de febrero de 2013 a las 17:33

No, no hay diferencia (si no te importa el valor de retorno).

El código de esos métodos (en OpenJDK) difiere solo en que uno usa return next y los otros usos return current.

Ambos usan compareAndSet bajo el capó con exactamente el mismo algoritmo. Ambos necesitan saber tanto el valor antiguo como el nuevo.

Solo quiero agregar a las respuestas existentes: podría haber una diferencia muy pequeña que no se nota.

Si miras esta implementación:

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

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

Nota: ambas funciones llaman exactamente a la misma función getAndAddIntexcepto +1 parte, lo que significa que en esta implementación getAndIncrement es más rápido.

Pero, aquí está implementación anterior:

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;
    }
}

La única diferencia es la variable de retorno, por lo que ambas funciones realizan exactamente lo mismo.

Avatar de usuario de Ajju_bhai
ajju_bhai

Aquí estoy dando un ejemplo. Espero que te aclare la duda.

Supongamos que tengo una variable i como

Entero atómico i = nuevo Entero atómico ();

En este caso:

i.getAndIncrement() i++;

Y

i.incrementarYObtener() ++i;

Por favor, eche un vistazo a los siguientes programas

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

    }

}

**producción

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

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

    }

}

**producción

0 1 ————-**

Comentario: 1) En la clase Test1, incrementAndGet() primero incrementará el valor i y luego imprimirá.

2) En la clase Test2, getAndIncrement() primero imprimirá el valor i y luego lo incrementará.

Eso es todo.

  • Gracias por tu respuesta. Sin embargo, en su respuesta, el resultado realmente se usa (imprime). La pregunta es sobre una situación en la que “Cuando el valor de retorno no es de interés”

    – hyde

    5 de junio de 2017 a las 7:18


  • Gracias por tu respuesta. Sin embargo, en su respuesta, el resultado realmente se usa (imprime). La pregunta es sobre una situación en la que “Cuando el valor de retorno no es de interés”

    – hyde

    5 de junio de 2017 a las 7:18


¿Ha sido útil esta solución?