當涉及一種場景,線程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()。