Tại sao i++
không phải là nguyên tử trong Java?
Để hiểu sâu hơn một chút về Java, tôi đã cố gắng đếm tần suất vòng lặp trong các luồng được thực thi.
Vì vậy, tôi đã sử dụng một
private static int total = 0;
trong lớp học chính.
Tôi có hai chủ đề.
- Chủ đề 1: Bản in
System.out.println("Hello from Thread 1!");
- Chủ đề 2: Bản in
System.out.println("Hello from Thread 2!");
Và tôi đếm số dòng được in ra bởi sợi 1 và sợi 2. Nhưng số dòng của sợi 1 + dòng của sợi 2 không khớp với tổng số dòng được in ra.
Đây là mã của tôi:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Test {
private static int total = 0;
private static int countT1 = 0;
private static int countT2 = 0;
private boolean run = true;
public Test() {
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
newCachedThreadPool.execute(t1);
newCachedThreadPool.execute(t2);
try {
Thread.sleep(1000);
}
catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
run = false;
try {
Thread.sleep(1000);
}
catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println((countT1 + countT2 + " == " + total));
}
private Runnable t1 = new Runnable() {
@Override
public void run() {
while (run) {
total++;
countT1++;
System.out.println("Hello #" + countT1 + " from Thread 2! Total hello: " + total);
}
}
};
private Runnable t2 = new Runnable() {
@Override
public void run() {
while (run) {
total++;
countT2++;
System.out.println("Hello #" + countT2 + " from Thread 2! Total hello: " + total);
}
}
};
public static void main(String[] args) {
new Test();
}
}
iinc
hoạt động để tăng số nguyên, nhưng điều đó chỉ hoạt động cho các biến cục bộ, nơi mà sự đồng thời không phải là mối quan tâm. Đối với các trường, trình biên dịch tạo các lệnh đọc-sửa đổi-ghi một cách riêng biệt.
iinc
lệnh cho các trường, việc có một lệnh duy nhất không đảm bảo tính nguyên tử, ví dụ như truy cập trường không volatile
long
và double
trường không được đảm bảo là nguyên tử bất kể thực tế là nó được thực hiện bởi một lệnh bytecode.
AtomicInteger
?