[英]Java synchronization: synchronized, wait(), notify()
我試圖理解Java中的線程間通信,並通過使用wait()
, notify()
, notifyAll()
方法來讀取支持。
為了使線程執行這些方法中的任何一個,該線程必須是線程正在為其調用(任何一個)方法的對象lock
所有者。 除此之外,所有這些方法都必須處於synchronized
塊/方法中。 到目前為止很好。
我試圖實現一個程序,其中一個線程打印奇數,而另一個線程打印偶數。
該程序可以正常運行,但是與此同時,它引起了更多疑問。
以下是我實現的程序的完整源代碼。
package com.example.multithr.implrun;
import com.example.common.ObjectToWaitOn;
public class PrintEvenNumThread implements Runnable {
private ObjectToWaitOn objectToWaitOn;
public PrintEvenNumThread(ObjectToWaitOn objectToWaitOn) {
this.objectToWaitOn = objectToWaitOn;
}
@Override
public void run() {
int numToPrint = 2;
for (;;) {
synchronized (objectToWaitOn) {
while(objectToWaitOn.getPrintEvenOrOdd() != 2) {
try {
objectToWaitOn.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
objectToWaitOn.print("EvenThread",numToPrint);
numToPrint += 2; // Generate next even number
objectToWaitOn.setPrintEvenOrOdd(1);
objectToWaitOn.notifyAll();
}
}
}
}
package com.example.multithr.implrun;
import com.example.common.ObjectToWaitOn;
public class PrintOddNumsThread implements Runnable {
private ObjectToWaitOn objectToWaitOn;
public PrintOddNumsThread(ObjectToWaitOn objectToWaitOn) {
this.objectToWaitOn = objectToWaitOn;
}
@Override
public void run() {
int numToPrint = 1;
for(;;) {
synchronized(objectToWaitOn) {
while(objectToWaitOn.getPrintEvenOrOdd() != 1) {
try {
objectToWaitOn.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
objectToWaitOn.print("OddThread", numToPrint);
numToPrint += 2; // Generate next odd number
objectToWaitOn.setPrintEvenOrOdd(2);
objectToWaitOn.notifyAll();
}
}
}
}
package com.vipin.common;
public class ObjectToWaitOn {
private int printEvenOrOdd;
public ObjectToWaitOn(int printEvenOrOdd) {
this.printEvenOrOdd = printEvenOrOdd;
}
public int getPrintEvenOrOdd() {
return printEvenOrOdd;
}
public void setPrintEvenOrOdd(int printEvenOrOdd) {
this.printEvenOrOdd = printEvenOrOdd;
}
public void print(String byThread, int numToPrint) {
System.out.println(byThread + ": " +numToPrint);
}
}
package com.example.multithr.main.app1;
import com.example.common.ObjectToWaitOn;
import com.example.multithr.implrun.PrintEvenNumThread;
import com.example.multithr.implrun.PrintOddNumsThread;
public class PrintEvenOddNumsMainApp {
public static void main(String[] args) {
ObjectToWaitOn obj = new ObjectToWaitOn(1); // 1 == odd; 2 == even
PrintEvenNumThread printEvenNumThread = new PrintEvenNumThread(obj);
PrintOddNumsThread printOddNumsThread = new PrintOddNumsThread(obj);
Thread evenNum = new Thread(printEvenNumThread);
Thread oddNum = new Thread(printOddNumsThread);
evenNum.start();
oddNum.start();
}
}
1)當這些線程中的任何一個通過在對象objectToWaitOn
(在這些線程之間共享notifyAll()
上調用notifyAll()
來釋放鎖時,是否立即釋放鎖? 我對此有疑問,因為這些線程位於基於objectToWaitOn
對象的synchronized
塊中; 因此,即使線程調用notifyAll(), 它是否也不應該保持鎖,因為它處於同步塊中 ?
2)當一個線程是通過調用等待條件wait()
上objectToWaitOn
,如果其他線程調用釋放鎖notifyAll()
不等待線程等待鎖釋放或其他什么東西? 從synchronized
塊中出來的線程是否不會釋放它持有的對象上的鎖; 因此,在上面的示例中,如果線程持有對objectToWaitOn
鎖定並退出了synchronized
塊,那么它是否仍不釋放objectToWaitOn
的鎖定,並且不應基於此喚醒另一個線程嗎?
誰能幫助我澄清這些疑問?
它會立即釋放鎖嗎?
不,不是。 線程繼續在同步塊內執行下一個語句。
它不應該因為處於同步塊中而仍然持有該鎖嗎?
是的,應該。 調用notify
/ notifyAll
方法的線程必須持有該鎖,並將繼續持有該鎖,直到它正常離開同步塊或發生異常為止:
- 如果Block的執行正常完成 ,則監視器將解鎖,並且synced語句將正常完成。
- 如果由於某種原因突然終止了該塊的執行,則監視器將被解鎖,並且由於相同的原因,同步語句也會突然完成。
JLS-14.19
notify
/ notifyAll
方法將在此監視器上等待的線程1的狀態從State.WAITING
為State.RUNNABLE
。 當線程喚醒時,它們可以參與獲取鎖。
來到監視器時,其中一些2可能會獲得STATE.BLOCKED
狀態,並等待其他線程釋放鎖。 請注意,它不需要持有鎖的線程的任何通知。
在當前線程放棄該對象上的鎖之前,喚醒的線程將無法繼續。 喚醒的線程將以通常的方式與可能正在主動競爭以在此對象上進行同步的任何其他線程競爭。 例如,被喚醒的線程在成為鎖定該對象的下一個線程時沒有任何可靠的特權或劣勢 。
docs
1.如果是notify
,則它是一個任意選擇的線程。
2.或所有這些-如果通知的線程一直保持着監視器。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.