併發 · 五 —— 使用wait()、notify()、notityAll()實現線程之間的協作

    當涉及一種場景,線程A需要等待線程B完成工作後再開始工作,這時就需要使用到Object基類中的wait()、notify()和notifyAll()來實現,先上例子

public class text {
	
	volatile static boolean ok = false; 
	
	static Object object = new Object();
	
	public static void main(String[] args) {
		
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				synchronized (object) { // 如果不加鎖,會報錯IllegalMonitorStateException
					System.err.println("進入同步");
					while (!ok) {
							System.err.println("開始等待");
						try {
							object.wait();
							System.out.println("結束等待");
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}
			}
		}).start();
		
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				synchronized (object) {
					System.out.println("通知停止等待");
					ok = true;
					object.notifyAll();
				}
				
			}
		}).start();
		
	}		
}

輸出結果:

進入同步
開始等待
通知停止等待
結束等待

 

有幾個注意點:

1、要在同步代碼(方法)中纔可以使用,即要獲得對象的鎖,才能可以使用該對象wait()、notify()、notifyAll();如果沒有在同步代碼中就是報IllegalMonitorStateException錯誤。

note:正因爲這種機制的設定,這個三個方法被放在Object基類中,而不是像sleep()方法放在Thread類中,所以當使用sleep()無需在同步代碼(方法)中。

2、配合while使用,可以判斷是否滿足條件,如果不滿足就繼續等待。例如上面的例子,變量ok,如果不賦值爲true,第一條線程將繼續等待。

3、notify()和notifyAll()的區別,notify()喚醒其中任意一個正處於等待的線程,而notifyAll()喚醒所有正處等待的線程。所有使用notifyAll()比使用notify()更加安全,嚴謹。

4、notify()和notifyAll()只能喚醒相應對象的wait()。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章