2012-01-16 36 views

Respuesta

13

La elección de estos dos tipos no debe depender del rendimiento. La elección principal para AtomicInteger es si desea lograr seguridad de hilo con las operaciones en el entero.

Sin embargo, la diferencia de rendimiento puede depender en gran medida del sistema operativo elegido, ya que la implementación detallada de las operaciones atómicas depende del sistema operativo.

+3

+1. AtomicInteger también proporciona un entero mutable barato, incluso en un caso de uso no simultáneo. –

+0

-1: AtomicInteger existe principalmente por razones de rendimiento (para implementar estructuras de datos sin bloqueo). Si la seguridad era la única preocupación, simplemente podría usar la sincronización. –

+2

@MichaelBorgwardt: el hecho de que la seguridad de las hebras sea posible con solo la sincronización no significa que AtomicInteger no proporcione operaciones enteras seguras para subprocesos. El punto de la respuesta es que el rendimiento bruto de Integer y AtomicInteger no es lo que guía la elección de uno u otro. Lo que guía la elección es el uso previsto: ¿necesitamos un entero mutable seguro para subprocesos, o simplemente queremos convertir un número entero en un objeto inmutable? –

1

Aparte de la sobrecarga de sincronización muy pequeña, no.

5

Bueno, si lo usa en entornos multiproceso, como, por ej. mostrador, entonces usted tiene que synchronize acceso al entero

public final class Counter { 
    private long value = 0; 
    public synchronized long getValue() { 
    return value; 
    } 

    public synchronized long increment() { 
    return ++value; 
    } 
} 

Mientras que usted puede tener un rendimiento mucho mejor con AtomicInteger sin sincronización

public class NonblockingCounter { 
    private AtomicInteger value; 

    public int getValue() { 
     return value.get(); 
    } 

    public int increment() { 
     return value.incrementAndGet(); 
    } 
} 

Lecturas recomendadas http://cephas.net/blog/2006/09/06/atomicinteger/

EDITAR uso incrementAndGet

+0

¿Por qué no usar incrementAndGet? –

+0

te refieres a [getAndIncrement] (http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicInteger.html#getAndIncrement())? Bueno, buena pregunta, señor, creo que fui demasiado rápido y flojo. – bpgergo

+0

No, me refiero a incrementAndGet. getAndIncrement sería equivalente a devolver i ++. Pero tu primer fragmento vuelve +++; –

3

AtomicInteger permite algunos (¡no todas!) operaciones que de otro modo requerirían que la sincronización se realizara sin bloqueos usando instrucciones de hardware especiales. Cómo esto afecta el rendimiento es un tanto complejo:

  • En primer lugar, se trata de una micro-optimización que solo importará si esta operación en particular está en la ruta crítica de su aplicación.
  • Las instrucciones especiales de hardware pueden no estar disponibles en plataformas no convencionales, en cuyo caso AtomicInteger probablemente se implementará mediante la sincronización.
  • La JVM a menudo puede optimizar los gastos generales de bloqueo cuando no hay contención (por ejemplo, una sola aplicación de subprocesos). En ese caso, probablemente no haya diferencia.
  • Si hay un conflicto de bloqueo de bajo a moderado (es decir, varios subprocesos, pero en su mayoría hacen otras cosas además de simplemente acceder a ese entero), el algoritmo sin bloqueo funciona mejor que la sincronización.
  • Si hay una contención de bloqueo muy pesada (es decir, muchos subprocesos que pasan mucho tiempo tratando de acceder a ese entero), la sincronización puede funcionar mejor porque el algoritmo de bloqueo se basa en reintentar constantemente la operación cuando falla debido a una colision.
+1

Exactamente los tipos de hechos que he estado buscando. Gracias. –

0

encontré con este anuncio de hoy, pero quería compartir mis resultados (Por favor, no hay comentarios en código como que tenía a mano escriba las siguientes clases como el sistema me encontré con éste en que no estaba conectado a internet :)

línea inferior la salida del código de abajo fue el siguiente:

resultados

atómico: transcurrido = 25257 ms, ExpectedValue = 50.000, FinalValue = 50000, verdaderos resultados primitiva: transcurrido = 25257 ms, ExpectedValue = 50.000, FinalValue = 48991, falso

Para mi uso en mi aplicación particular, he elegido usar valores atómicos para los números de estado en una clase de monitoreo.En caso de que alguien más quisiera ver algunos resultados difíciles, opté por publicar esta información.

¡Que tengas un gran día!

Clases:

he creado una clase principal con una larga primitivo y un atómicas métodos de incremento de longitud y de descriptor de acceso, un IncrementAtomicRunnable y un IncrementPrimitiveRunnable.

LongOverhead:

public class LongOverhead{ 
    AtomicLong atomicLong; 
    long primitiveLong; 

    public LongOverhead(){ 
    atomicLong = new AtomicLong(0l); 
    primitiveLong = 0l; 
    } 

    public void incrAtomicLong(){ 
    atomicLong.getAndAdd(1l); 
    } 

    public long getAtomicLong(){ 
    return atomicLong.get(); 
    } 

    public void incrPrimitiveLong(){ 
    primitiveLong++; 
    } 

    public long getPrimitiveLong(){ 
    return primitiveLong; 
    } 

    public static void main(String [] args){ 
    String template = "%s Results: Elapsed = %d ms, ExpectedValue = %d, FinalValue = %d, %b"; 

    int loopTotal = 1000; 
    int waitMilliseconds = 25; 
    int totalThreads = 50; 
    int expectedValue = loopTotal * totalThreads; 
    int whileSleep = 250; 

    LongOverhead atomic = new LongOverhead(); 
    LongOverhead primitive = new LongOverhead(); 

    List<Thread> atomicThreads = new ArrayList<>(); 
    List<Thread> primitiveThreads = new ArrayList<>(); 

    for(int x=0;x<totalThreads;x++){ 
     Thread a = new Thread(new IncrementalAtomicRunnable(atomic, loopTotal, waitMilliseconds), "AtomicIncr" + x); 
     atomicThreads.add(a); 

     Thread p = new Thread(new IncrementalPrimitiveRunnable(primitive, loopTotal, waitMilliseconds), "PrimitiveIncr" + x); 
     primitiveThreads.add(p); 
    } 

    boolean cont = true; 
    long atomicStart = System.currentTimeMillis(); 
    for(Thread t: atomicThreads){ 
     t.start(); 
    } 

    while(cont){ 
     try{ 
     Thread.sleep(whileSleep); 
     }catch(InterruptedException e){ 
     e.printStackTrace(); 
     } 

     boolean foundAlive = false; 
     for(Thread t: atomicThreads){ 
     foundAlive = (State.TERMINATED != t.getState()); 
     if(foundAlive){ 
      break; 
     } 
     } 

     cont = foundAlive; 

    } 

    long atomicFinish = System.currentTimeMillis(); 
    long atomicElapsed = atomicFinish - atomicStart; 
    long atomicFinal = atomic.getAtomicLong(); 

    cont = true; 
    long primitiveStart = System.currentTimeMillis(); 
    for(Thread t: primitiveThreads){ 
     t.start(); 
    } 

    while(cont){ 
     try{ 
     Thread.sleep(whileSleep); 
     }catch(InterruptedException e){ 
     e.printStackTrace(); 
     } 

     boolean foundAlive = false; 
     for(Thread t: primitiveThreads){ 
     foundAlive = (State.TERMINATED != t.getState()); 
     if(foundAlive){ 
      break; 
     } 
     } 

     cont = foundAlive; 
    long primitiveFinish = System.currentTimeMillis(); 
    long primitiveElapsed = primitiveFinish - primitiveStart; 
    long primitiveFinal = primitive.getPrimitiveLong(); 

    System.out.println(String.format(template, "ATOMIC", atomicElapsed, expectedValue, atomicFinal, (expectedValue==atomicFinal))); 
    System.out.println(String.format(template, "PrImItIvE", primitiveElapsed, expectedValue, primitiveFinal, (expectedValue==primitiveFinal))); 
    } 

IncrementAtomicRunnable:

public class IncrementAtomicRunnable implements Runnable{ 
    protected LongOverhead oh; 
    protected int loopTotal; 
    protected int waitMilliseconds; 
    protected String currentThreadName; 

    public IncrementAtomicRunnable(LongOverhead oh, int loopTotal, int waitMilliseconds){ 
    this.oh = oh; 
    this.loopTotal = loopTotal; 
    this.waitMilliseconds = waitMilliseconds; 
    } 

    @Override 
    public void run(){ 
    currentThreadName = Thread.currentThread().getName(); 
    System.out.println(currentThreadName + " for ATOMIC is starting....."); 
    for(int x=0;x<loopTotal;x++){ 
     oh.incrAtomicLong(); 
     try{ 
     Thread.sleep(waitMilliseconds); 
     }catch(InterruptedException e){ 
     System.out.println("InterruptedThread[" + currentThreadName + "], eating exception @@@@@"); 
     } 
    } 

    System.out.println("....." + currentThreadName + " for ATOMIC is finished."); 
    } 
} 

y finalmente IncrementPrimitiveRunnable:

public class IncrementPrimitiveRunnable extends IncrementAtomicRunnable{ 
    public IncrmentPrimitiveRunnable(LongOverhead oh, int loopTotal, int waitMilliseconds){ 
    super(oh, loopTotal, waitMilliseconds); 
    } 

    @Override 
    public void run(){ 
    super.currentThreadName = Thread.currentThread().getName(); 
    System.out.println(currentThreadName + " for PRIMITIVE is starting....."); 
    for(int x=0;x<loopTotal;x++){ 
     oh.incrPrimitiveLong(); 
     try{ 
     Thread.sleep(waitMilliseconds); 
     }catch(InterruptedException e){ 
     System.out.println("InterruptedThread[" + currentThreadName + "], eating exception @@@@@"); 
     } 
    } 

    System.out.println("....." + currentThreadName + " for PRIMITIVE is finished."); 
    } 
}