Zgadzam się z @ odpowiedzi Kumara.
Niestabilność nie jest wystarczająca - ma pewne implikacje dla kolejności w pamięci, ale nie zapewnia atomowości ++.
Naprawdę trudną rzeczą w programowaniu wielowątkowym jest to, że problemy mogą nie pojawić się w rozsądnej ilości testów. Napisałem program do zademonstrowania problemu, ale ma wątki, które nie robią nic poza licznikami przyrostu. Mimo to liczba ta wynosi około 1% prawidłowej odpowiedzi. W prawdziwym programie, w którym wątki mają inne zadanie do wykonania, może istnieć bardzo małe prawdopodobieństwo, że dwa wątki wykonają ++ wystarczająco blisko, aby jednocześnie pokazać problem. Poprawności wielowątkowości nie można przetestować, należy ją zaprojektować.
Ten program wykonuje to samo zadanie zliczania, używając prostego statycznego int, lotnego int i AtomicInteger. Tylko AtomicInteger konsekwentnie otrzymuje właściwą odpowiedź. Typowa moc na wieloprocesorowych z 4 podwójnymi rdzenie to:
count: 1981788 volatileCount: 1982139 atomicCount: 2000000 Expected count: 2000000
Oto kod źródłowy:
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();
}
}
}
}
trzeba chronić jednoczesnych dostępów do obiekt 'int' siebie. Ale 'AtomicInteger' został zaprojektowany tak, aby był bezpieczny dla wątków. – reprogrammer
'static' nie ma nic wspólnego z multi-threading. –
O ile mi wiadomo, używamy zmienne lotne zamiast zmiennych statycznych w środowiskach wielowątkowych. – Vishal