[英]Multiple threads showing excepted value when System.out.println is presented in critical section
我有以下代碼:
public class MyApp {
public static void main(String[] args) throws InterruptedException {
SharedResource sharedResource = new SharedResource();
Runnable first = () -> {
sharedResource.increment(10000);
};
Runnable second = () -> {
sharedResource.increment(10000);
};
Thread thread = new Thread(first, "FirstThread");
Thread thread2 = new Thread(second, "SecondThread");
thread.start();
thread2.start();
thread.join();
thread2.join();
System.out.println("The value of counter is " + sharedResource.getCounter());
}
}
使用這個類:
public class SharedResource {
private int counter;
public void increment(int times) {
for (int x=1; x<=times;x++) {
counter++;
// System.out.println(counter);
}
}
public void decrement() {
counter--;
}
public int getCounter() {
return counter;
}
}
我很好奇為什么會一直這樣。
從increment方法中刪除System.out.println()
的總值
System.out.println("The value of counter is " + sharedResource.getCounter());
是隨機的 - 這是例外,因為多個線程共享同一個counter
。
但是,當System.out.println(counter);
在增量方法上呈現,代碼似乎不再具有多線程問題。
計數器的最終結果總是20,000,因為代碼從每個線程中丟失了10,000次。 任何人都可以解釋我為什么會這樣嗎?
這是由於非常小的比賽窗口。
默認系統輸出是PrintStream,它是線程安全的:
public void println(int x) {
synchronized (this) {
print(x);
newLine();
}
}
所以基本上線程執行以下操作:
當你的關鍵部分比非關鍵部分長1000倍時,你的線程基本上是序列化的,並且計數器更新重疊的概率變得非常小,系統輸出沒有什么特別之處。
方法證明:
您可以編寫PrintStream的線程安全實現:
public class NullPrintStream extends PrintStream { public NullPrintStream() { // Utility constant from apache-commons super(NullOutputStream.NULL_OUTPUT_STREAM); } @Override public void println(int x) { // No synchronization here } }
然后通過System.setOut(new NullPrintStream())
將其設置為系統輸出,結果將再次開始拍打。
要在開始時提供更大的競賽窗口,您可以在latch上同步runnables,以便它們幾乎同時啟動:
CountDownLatch latch = new CountDownLatch(1); Runnable first = () -> { try { latch.await(); sharedResource.increment(10000); } catch (Exception e) { } }; // ... start your threads here latch.countDown();
然后,如果你運行這個樣本幾次,你會看到類似的東西(請注意我將它打印到System.err
因為我已經覆蓋了System.out
)
計數器的值是20000
計數器的價值是19996
計數器的價值是19994
計數器的價值是19999
計數器的值是20000
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.