一、對于wait()和notify()的解釋
void notify()
Wakes up a single thread that is waiting on this object’s monitor.
喚醒等待擷取鎖資源的單個線程
void notifyAll()
Wakes up all threads that are waiting on this object’s monitor.
喚醒等待擷取鎖資源的所有線程
void wait( )
Causes the current thread to wait until another thread invokes the notify() method or the notifyAll( ) method for this object.
釋放出對象的鎖資源,程式會阻塞在這裡
二、使用wait()、notify()、notifyAll()應該要注意的地方
1、wait( ),notify( ),notifyAll( )都不屬于Thread類,屬于Object基礎類,每個對象都有wait( ),notify( ),notifyAll( ) 的功能,因為每個對象都有鎖
2、當需要調用wait( ),notify( ),notifyAll( )的時候,一定都要在synchronized裡面,不然會報 IllegalMonitorStateException 異常,可以這樣了解,在synchronized(object) {}裡面的代碼才能擷取到對象的鎖。
3、while循環裡而不是if語句下使用wait,這樣,會線上程暫停恢複後都檢查wait的條件,并在條件實際上并未改變的情況下處理喚醒通知
4、調用obj.wait( )釋放了obj的鎖,程式就會阻塞在這裡,如果後面被notify()或者notifyAll()方法呼喚醒了之後,那麼程式會接着調用obj.wait()後面的程式。
5、notify()喚醒等待擷取鎖資源的單個線程,notifyAll( )喚醒等待擷取鎖資源的所有線程
6、當調用obj.notify/notifyAll後,調用線程依舊持有obj鎖,其它線程仍無法獲得obj鎖,直到調用線程退出synchronized塊或者在原有的obj調用wait釋放鎖,其它的線程才能起來
三、使用wait()、notify()、notifyAll()實作非阻塞式的消費者和生産者
package wait;
import java.util.PriorityQueue;
public class WaitAndNofityTest {
public static final int COUNT = 5;
//優先隊列,消費者在這個隊列裡面消耗資料,生産者在這個裡面生産資料
public PriorityQueue<Integer> queue = new PriorityQueue<Integer>(COUNT);
public static void main(String[] args) {
WaitAndNofityTest waitAndNofityTest = new WaitAndNofityTest();
Cus cus = waitAndNofityTest.new Cus();
Make make = waitAndNofityTest.new Make();
make.start();
cus.start();
}
//消費者線程類
class Cus extends Thread {
@Override
public void run() {
System.out.println("Cus queue size is:" + queue.size());
eatData();
}
public void eatData() {
while (true) {
synchronized (queue) {
System.out.println("go to eatData method size is:" + queue.size());
while (queue.size() == 0) {
try {
System.out.println("Cus start notify");
queue.notify();
System.out.println("Cus start wait");
queue.wait();
System.out.println("Cus wait after");
} catch (InterruptedException e) {
queue.notify();
}
}
queue.poll();
System.out.println("Cus eatData after size is:" + queue.size());
}
}
}
}
//生産者線程類
class Make extends Thread {
@Override
public void run() {
System.out.println("Make queue size is:" + queue.size());
addData();
}
public void addData() {
while (true) {
synchronized (queue) {
System.out.println("go to addData method size is:" + queue.size());
while (queue.size() == COUNT) {
try {
System.out.println("Make start notify");
queue.notify();
System.out.println("Make start wait");
queue.wait();
System.out.println("Make wait after");
} catch (InterruptedException e) {
queue.notify();
}
}
queue.offer(5);
System.out.println("Cus addData after size is:" + queue.size());
}
}
}
}
}
四、部分運作結果
Cus addData after size is:5
go to addData method size is:5
Make start notify
Make start wait
Cus wait after
Cus eatData after size is:4
go to eatData method size is:4
Cus eatData after size is:3
go to eatData method size is:3
Cus eatData after size is:2
go to eatData method size is:2
Cus eatData after size is:1
go to eatData method size is:1
Cus eatData after size is:0
go to eatData method size is:0
Cus start notify
Cus start wait
Make wait after
Cus addData after size is:1
go to addData method size is:1
Cus addData after size is:2
go to addData method size is:2
Cus addData after size is:3
go to addData method size is:3
Cus addData after size is:4
go to addData method size is:4
Cus addData after size is:5
go to addData method size is:5
Make start notify
Make start wait
Cus wait after
Cus eatData after size is:4
go to eatData method size is:4
Cus eatData after size is:3
go to eatData method size is:3
Cus eatData after size is:2
go to eatData method size is:2
Cus eatData after size is:1
go to eatData method size is:1
Cus eatData after size is:0
go to eatData method size is:0
Cus start notify
Cus start wait
Make wait after
Cus addData after size is:1
go to addData method size is:1
Cus addData after size is:2
go to addData method size is:2
Cus addData after size is:3
go to addData method size is:3
Cus addData after size is:4
go to addData method size is:4
Cus addData after size is:5
go to addData method size is:5
Make start notify
Make start wait
Cus wait after
Cus eatData after size is:4
go to eatData method size is:4
Cus eatData after size is:3
go to eatData method size is:3
Cus eatData after size is:2
go to eatData method size is:2
Cus eatData after size is:1
go to eatData method siz
如果運作了不了解,你可以自己測試然後分析列印的資料,當然你也可以注釋掉2個類裡面的任意一個notify方法,然後看是什麼效果,是不是和自己分析的結果一樣,同樣你也可以去掉第一類的wait方法試下,看執行notify方法後是synchronized執行完了呼喚其其它線程或則在調用wait方法之後釋放鎖後是否也會呼喚其線程?
五、用ArrayBlockingQueue實作阻塞式的生産者和消費者
package wait;
import java.util.concurrent.ArrayBlockingQueue;
public class BlockTest {
private int COUNT = 5;
private ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(COUNT);
public static void main(String[] args) {
BlockTest test = new BlockTest();
Make make = test.new Make();
Cus cus = test.new Cus();
make.start();
cus.start();
}
class Cus extends Thread {
@Override
public void run() {
eatData();
}
private void eatData() {
while (true) {
try {
queue.take();
System.out.println("隊列取一個元素,隊列剩餘"+queue.size() + "元素");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Make extends Thread {
@Override
public void run() {
addData();
}
private void addData() {
while(true){
try {
queue.put(5);
System.out.println("隊列插入一個元素,隊列剩餘空間:" + (COUNT-queue.size()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
六、部分運作結果
隊列取一個元素,隊列剩餘4元素
隊列取一個元素,隊列剩餘3元素
隊列取一個元素,隊列剩餘2元素
隊列取一個元素,隊列剩餘1元素
隊列取一個元素,隊列剩餘0元素
隊列插入一個元素,隊列剩餘空間:4
隊列插入一個元素,隊列剩餘空間:3
隊列插入一個元素,隊列剩餘空間:2
隊列插入一個元素,隊列剩餘空間:1
隊列插入一個元素,隊列剩餘空間:0
隊列取一個元素,隊列剩餘4元素
隊列取一個元素,隊列剩餘3元素
隊列取一個元素,隊列剩餘2元素
隊列取一個元素,隊列剩餘1元素
隊列取一個元素,隊列剩餘0元素
隊列插入一個元素,隊列剩餘空間:4
隊列插入一個元素,隊列剩餘空間:3
隊列插入一個元素,隊列剩餘空間:2
隊列插入一個元素,隊列剩餘空間:1
隊列插入一個元素,隊列剩餘空間:0
隊列取一個元素,隊列剩餘4元素
隊列取一個元素,隊列剩餘3元素
隊列取一個元素,隊列剩餘2元素
隊列取一個元素,隊列剩餘1元素
隊列取一個元素,隊列剩餘0元素
隊列插入一個元素,隊列剩餘空間:4
隊列插入一個元素,隊列剩餘空間:3
隊列插入一個元素,隊列剩餘空間:2
隊列插入一個元素,隊列剩餘空間:1
隊列插入一個元素,隊列剩餘空間:0
隊列取一個元素,隊列剩餘4元素
隊列取一個元素,隊列剩餘3元素
隊列取一個元素,隊列剩餘2元素
隊列取一個元素,隊列剩餘1元素
隊列取一個元素,隊列剩餘0元素
隊列插入一個元素,隊列剩餘空間:4
隊列插入一個元素,隊列剩餘空間:3
隊列插入一個元素,隊列剩餘空間:2
隊列插入一個元素,隊列剩餘空間:1
隊列插入一個元素,隊列剩餘空間:0
隊列取一個元素,隊列剩餘4元素
隊列取一個元素,隊列剩餘3元素
隊列取一個元素,隊列剩餘2元素
隊列取一個元素,隊列剩餘1元素
隊列取一個元素,隊列剩餘0元素
隊列插入一個元素,隊列剩餘空間:4
隊列插入一個元素,隊列剩餘空間:3
隊列插入一個元素,隊列剩餘空間:2
隊列插入一個元素,隊列剩餘空間:1
隊列插入一個元素,隊列剩餘空間:0
隊列取一個元素,隊列剩餘4元素
隊列取一個元素,隊列剩餘3元素
隊列取一個元素,隊列剩餘2元素
隊列取一個元素,隊列剩餘1元素
隊列取一個元素,隊列剩餘0元素
隊列插入一個元素,隊列剩餘空間:4
隊列插入一個元素,隊列剩餘空間:3
隊列插入一個元素,隊列剩餘空間:2
隊列插入一個元素,隊列剩餘空間:1
隊列插入一個元素,隊列剩餘空間:0
隊列取一個元素,隊列剩餘4元素
隊列取一個元素,隊列剩餘3元素
隊列取一個元素,隊列剩餘2元素
隊列取一個元素,隊列剩餘1元素
隊列取一個元素,隊列剩餘0元素
隊列插入一個元素,隊列剩餘空間:4
隊列插入一個元素,隊列剩餘空間:3
隊列插入一個元素,隊列剩餘空間:2
隊列插入一個元素,隊列剩餘空間:1
隊列插入一個元素,隊列剩餘空間:0
隊列取一個元素,隊列剩餘4元素