2015-06-07 8 views
12

Vedo come funziona AtomicInteger di Java internamente con l'operazione CAS (Confronto e scambio). Fondamentalmente quando più thread tentano di aggiornare il valore, JVM utilizza internamente il meccanismo CAS sottostante e tenta di aggiornare il valore. Se l'aggiornamento fallisce, riprova con il nuovo valore ma non blocca mai.In che modo LongAdder ha prestazioni migliori di AtomicLong

In Java8 Oracle ha introdotto una nuova classe LongAdder che sembra funzionare meglio di AtomicInteger in alta contesa. Alcuni post del blog affermano che LongAdder ha prestazioni migliori mantenendo le celle interne. Ciò significa che LongAdder aggrega i valori internamente e lo aggiorna in un secondo momento? Potresti per favore aiutarmi a capire come funziona LongAdder?

+0

http://stackoverflow.com/questions/27628538/multithreading-summing-large-number-of-values-atomically/27628873#27628873 – sol4me

+0

In un primo momento penso che ho frainteso. Leggendo di nuovo la tua domanda, penso che tu abbia avuto l'idea giusta. – aioobe

+0

Grazie! Sono più interessato a capire come sono organizzate queste cellule interne? dire se 100 thread stanno cercando di aggiornare il valore, quante celle interne vengono create e come vengono aggiornate? – Sathish

risposta

5

significa che LongAdder aggrega i valori internamente e lo aggiorna in un secondo momento?

Sì, se ho compreso correttamente la tua dichiarazione.

Ogni Cell in un LongAdder è una variante di un AtomicLong. Avere più di queste celle è un modo per diffondere la contesa e quindi aumentare il throughput.

Quando il risultato finale (somma) deve essere recuperato, aggiunge semplicemente i valori di ciascuna cella.

Gran parte della logica intorno come sono organizzati cellule, ecc come vengono assegnati può essere visto nella fonte: http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/f398670f3da7/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java

In particolare il numero di cellule è vincolata dal numero di CPU:

/** Number of CPUS, to place bound on table size */ 
static final int NCPU = Runtime.getRuntime().availableProcessors(); 
2

La ragione principale per cui è "più veloce" è la prestazione contesa. Questo è importante perché:

Sotto contesa di aggiornamento bassa, le due classi hanno caratteristiche simili.

devi usare un LongAdder per gli aggiornamenti molto frequenti, in cui CAS atomica e chiamate native per Unsafe causerebbe contesa. (Vedere source e volatile reads). Per non parlare cache misses/false sharing su più AtomicLongs (anche se non ho ancora guardato il layout della classe, non sembra essere sufficiente imbottitura memoria prima della long campo vero e proprio.

sotto alta contesa, il throughput atteso di questa classe è notevolmente superiore, a scapito di una maggiore consumo di spazio.

l'attuazione estende Striped64, che è un supporto di dati per valori a 64 bit. I valori sono tenuti in cellule, che sono imbottiti (oa righe), quindi il nome. Ogni operazione può su LongAdder modificherà la collezione di valori presenti in Striped64 ention si verifica, una nuova cella viene creata e modificata, quindi il thread precedente può terminare contemporaneamente a quello contendente. Quando hai bisogno del valore finale, le somme di ogni cella vengono semplicemente sommate.

Sfortunatamente, le prestazioni hanno un costo, che in questo caso è la memoria (come spesso accade). Striped64 può diventare molto grande se viene caricato un grosso carico di thread e aggiornamenti.

fonte Citazione: Javadoc for LongAdder

Problemi correlati