目前CSDN,部落格園,簡書同步發表中,更多精彩歡迎通路我的gitee pages
wait,notify和notifyAll
總結
- 在調用wait方法時,線程必須要持有被調用對象的鎖,當調用wait方法後,線程就會釋放掉該對象的鎖(monitor)
- 在調用Thread類的sleep方法時,線程是不會釋放掉對象的鎖的
- 當調用wait時,首先需要確定調用了wait方法的線程已經持有了對象的鎖
- 當調用wait後,該線程就會釋放掉這個對象的鎖,然後進入到等待狀态(wait set)
- 當線程調用了wait後進入到等待狀态時,它就可以等待其他線程調用相同對象的notify或notifyAll方法來使得自己被喚醒
- 一旦這個線程被其他線程喚醒後,該線程就會與其他線程一同開始競争這個對象的鎖(公平競争);隻有當該線程擷取到了這個對象的鎖後,線程才會繼續往下執行
- 調用wait方法的代碼片段需要放在一個synchronized塊或是synchronized方法中,這樣才可以確定線程在調用wait方法前已經擷取到了對象的鎖
- 當調用對象的notify方法時,它會随機喚醒該對象等待集合(wait set)中的任意一個線程,當某個線程被喚醒後,它就會與其他線程一同競争對象的鎖
- 當調用對象的notifyAll方法時,它會喚醒該對象等待集合(wait set)中的所有線程,這些線程被喚醒後,又會開始競争對象的鎖
- 在某一時刻,隻有唯一一個線程可以擁有對象的鎖
案例
編寫一個多線程程式,實作這樣一個目标: - 存在一個對象,該對象有一個int類型的成員變量counter,該成員變量的初始值為0.
- 建立兩個線程,其中一個線程對該對象的成員變量counter增1,另一個線程對該對象的成員變量減1.
- 輸出該對象成員變量counter每次變化後的值.
- 最終輸出結果應為:101010101010…
- 建立一個普通類MyObject,有成員變量counter,有一個使counter++的方法和一個使counter–的方法.
public class MyObject {
private int counter;
public synchronized void increase() {
while (counter != 0) {
try {
wait();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
counter++;
System.out.print(counter);
notify();
}
public synchronized void decrease() {
while (counter == 0) {
try {
wait();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
counter--;
System.out.print(counter);
notify();
}
}
- 建立一個調用MyObject的increase方法的線程類IncreaseThread
public class IncreaseThread extends Thread {
private MyObject myObject;
public IncreaseThread(MyObject myObject) {
this.myObject = myObject;
}
@Override
public void run() {
for (int i = 0; i < 30; ++i) {
try {
Thread.sleep((long)(Math.random() * 1000));
} catch (InterruptedException ex) {
ex.printStackTrace();
}
myObject.increase();
}
}
}
- 建立一個調用MyObject的decrease方法的線程類DecreaseThread
public class DecreaseThread extends Thread {
private MyObject myObject;
public DecreaseThread(MyObject myObject) {
this.myObject = myObject;
}
@Override
public void run() {
for (int i = 0; i < 30; ++i) {
try {
Thread.sleep((long)(Math.random() * 1000));
} catch (InterruptedException ex) {
ex.printStackTrace();
}
myObject.decrease();
}
}
}
public class Client {
public static void main(String[] args) {
MyObject myObject = new MyObject();
Thread increaseThread = new IncreaseThread(myObject);
Thread increaseThread2 = new IncreaseThread(myObject);
Thread decreaseThread = new DecreaseThread(myObject);
Thread decreaseThread2 = new DecreaseThread(myObject);
increaseThread.start();
increaseThread2.start();
decreaseThread.start();
decreaseThread2.start();
}
}