Sono d'accordo con @ risposta di Kumar.
Volatile non è sufficiente - ha alcune implicazioni per l'ordine di memoria, ma non garantisce l'atomicità di ++.
La cosa veramente difficile della programmazione multi-thread è che i problemi potrebbero non essere visualizzati in una quantità ragionevole di test. Ho scritto un programma per dimostrare il problema, ma ha thread che non fanno altro che incrementare i contatori. Anche così, i conteggi sono all'interno di circa l'1% della risposta giusta. In un programma reale, in cui i thread hanno altro lavoro da fare, ci può essere una probabilità molto bassa di due thread che fanno il ++ abbastanza vicino da mostrare simultaneamente il problema. La correttezza multi-thread non può essere testata, deve essere progettata in.
Questo programma esegue lo stesso compito di conteggio utilizzando un semplice int statico, un volatile int e un AtomicInteger. Solo AtomicInteger ottiene sempre la risposta giusta. Un output tipico su un multiprocessore con 4 core dual-threaded è:
count: 1981788 volatileCount: 1982139 atomicCount: 2000000 Expected count: 2000000
Ecco il codice sorgente:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class Test {
private static int COUNTS_PER_THREAD = 1000000;
private static int THREADS = 2;
private static int count = 0;
private static volatile int volatileCount = 0;
private static AtomicInteger atomicCount = new AtomicInteger();
public static void main(String[] args) throws InterruptedException {
List<Thread> threads = new ArrayList<Thread>(THREADS);
for (int i = 0; i < THREADS; i++) {
threads.add(new Thread(new Counter()));
}
for (Thread t : threads) {
t.start();
}
for (Thread t : threads) {
t.join();
}
System.out.println("count: " + count + " volatileCount: " + volatileCount + " atomicCount: "
+ atomicCount + " Expected count: "
+ (THREADS * COUNTS_PER_THREAD));
}
private static class Counter implements Runnable {
@Override
public void run() {
for (int i = 0; i < COUNTS_PER_THREAD; i++) {
count++;
volatileCount++;
atomicCount.incrementAndGet();
}
}
}
}
fonte
2012-11-28 07:01:49
Dovete proteggere accessi concorrenti a un 'int' te stesso. Ma, 'AtomicInteger' è progettato per essere thread-safe. – reprogrammer
'static' non ha nulla a che fare con il multi-threading. –
Per quanto ne so, utilizziamo variabili volatili anziché variabili statiche in ambienti con multithreading. – Vishal