[英]DelayQueue unexpected behavior. DrainTo deletes from the queue only 1 expired item
[英]Unexpected thread behavior. Visibility
我有以下代碼:
public static boolean turn = true;
public static void main(String[] args) {
Runnable r1 = new Runnable() {
public void run() {
while (true) {
while (turn) {
System.out.print("a");
turn = false;
}
}
}
};
Runnable r2 = new Runnable() {
public void run() {
while (true) {
while (!turn) {
System.out.print("b");
turn = true;
}
}
}
};
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
在課堂上,我們了解了使用非同步代碼時可能發生的“可見性”問題。 我知道,為了節省時間,編譯器將為循環決定對CPU緩存的抓取turn
,這意味着線程不會知道RAM中的turn
值是否已更改,因為他不檢查它。
據我了解,我希望代碼像這樣運行:
T1將看到轉為true->進入循環並打印->將轉為false->被卡住
T2會認為轉彎沒有改變->會被卡住
我希望如果T1在T2之前開始:只會打印'a',並且兩個線程都將在無限循環中運行而無需打印其他任何內容
但是,當我運行代碼時,有時我會在兩個線程卡住之前得到一些“ abab ....”。
我想念什么?
編輯:
以下代碼完成了我所期望的:線程將在無限循環中運行:
public class Test extends Thread {
boolean keepRunning = true;
public void run() {
long count = 0;
while (keepRunning) {
count++;
}
System.out.println("Thread terminated." + count);
}
public static void main(String[] args) throws InterruptedException {
Test t = new Test();
t.start();
Thread.sleep(1000);
t.keepRunning = false;
System.out.println("keepRunning set to false.");
}
}
它們彼此之間有何不同?
當我運行代碼時,有時我會在兩個線程卡住之前得到一些“ abab ....”。
我懷疑正在發生的事情是,在對代碼進行JIT編譯時,行為正在改變。 在JIT編譯之前,寫操作是可見的,因為解釋器正在執行寫操作。 在JIT編譯之后,緩存刷新或讀取已被優化……因為內存模型允許這樣做。
我想念什么?
您缺少的是您期望未指定的行為是一致的。 不一定是。 畢竟,它是未指定的! (這是正確的,即使我上面提出的解釋不正確。)
turn
不是不穩定的事實並不意味着您的代碼會中斷,而可能會中斷。 就我們所知,線程在任何給定時刻都可能看到false或true。 無需特別說明,就可以隨意清除緩存,線程可以保留其緩存等。
這可能是因為您的代碼正在遭受System.out.print
副作用,該副作用在內部寫入同步方法:
521 private void write(String s) {
522 try {
523 synchronized (this) {
( 資料來源-DocJar )
同步的內存影響可能會刷新緩存,因此會影響您的代碼。
正如@Stephen C所說,它也可能是JIT,它可能會進行布爾檢查,因為它假定值不會由於另一個線程而改變。
因此,在到目前為止提到的三種不同的可能性中,它們都可能是影響代碼行為的因素。 可見性是一個因素,而不是決定因素。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.