四、協作,互斥下的協作——Java多線程協作(wait、notify、notifyAll)
Java監視器支援兩種線程:互斥和協作。
前面我們介紹了採用對象鎖和重入鎖來實現的互斥。這一篇中,我們來看一看線程的協作。
舉個例子:有一家漢堡店舉辦吃漢堡比賽,決賽時有3個顧客來吃,3個廚師來做,一個服務員負責協調漢堡的數量。為了避免浪費,制 作好的漢堡被放進一個能裝有10個漢堡的長條狀容器中,按照先進先出的原則取漢堡。如果容器被裝滿,則廚師停止做漢堡,如果顧客發 現容器內的漢堡吃完了,就可以拍響容器上的鬧鈴,提醒廚師再做幾個漢堡出來。此時服務員過來安撫顧客,讓他等待。而一旦廚師的漢 堡做出來,就會讓服務員通知顧客,漢堡做好了,讓顧客繼續過來取漢堡。
這裡,顧客其實就是我們所說的消費者,而廚師就是生產者。容器是決定廚師行為的監視器,而服務員則負責監視顧客的行為。
在JVM中,此種監視器被稱為等待並喚醒監視器。
在這種監視器中,一個已經持有該監視器的線程,可以通過調用監視對象的wait方法,暫停自身的執行,並釋放監視器,自己進入一個 等待區,直到監視器內的其他線程調用了監視對象的notify方法。當一個線程調用喚醒命令以後,它會持續持有監視器,直到它主動釋放 監視器。而這之後,等待線程會蘇醒,其中的一個會重新獲得監視器,判斷條件狀態,以便決定是否繼續進入等待狀態或者執行監視地區 ,或者退出。
請看下面的代碼:
1.public class NotifyTest {
2.private String flag = "true";
3.
4.class NotifyThread extends Thread{
5.public NotifyThread(String name) {
6.super(name);
7.}
8.public void run() {
9.try {
10.sleep(3000);//延遲3秒鐘通知
11.} catch (InterruptedException e) {
12.e.printStackTrace();
13.}
14.
15.flag = "false";
16.flag.notify();
17.}
18.};
19.
20.class WaitThread extends Thread {
21.public WaitThread(String name) {
22.super(name);
23.}
24.
25.public void run() {
26.
27.while (flag!="false") {
28.System.out.println(getName() + " begin waiting!");
29.long waitTime = System.currentTimeMillis();
30.try {
31.flag.wait();
32.} catch (InterruptedException e) {
33.e.printStackTrace();
34.}
35.waitTime = System.currentTimeMillis() - waitTime;
36.System.out.println("wait time :"+waitTime);
37.}
38.System.out.println(getName() + " end waiting!");
39.
40.}
41.}
42.
43.public static void main(String[] args) throws InterruptedException {
44.System.out.println("Main Thread Run!");
45.NotifyTest test = new NotifyTest();
46.NotifyThread notifyThread =test.new NotifyThread("notify01");
47.WaitThread waitThread01 = test.new WaitThread ("waiter01");
48.WaitThread waitThread02 = test.new WaitThread("waiter02");
49.WaitThread waitThread03 = test.new WaitThread("waiter03");
50.notifyThread.start();
51.waitThread01.start();
52.waitThread02.start ();
53.waitThread03.start();
54.}
55.
56.}