java的wait()方法使用注意事項
1.本文解決的問題
(1)wait()方法一定要使用sycronized進行同步嗎?不用sycronized修飾會有什麼問題?
(2)wait()方法會釋放物件鎖,那麼這裡指的鎖是什麼?
(3)wait()會釋放物件鎖,而sleep()不會釋放物件鎖,這在實際情況中有什麼區別?
2.結論
(1)wait()一定要使用sycronized進行同步,否則會報“java.lang.IllegalMonitorStateException”異常。這是因為wait方法會釋放物件鎖,而此時因為沒有用sycronized同步,就沒有鎖,就會報異常。
(2)鎖指的是sycronized修飾的方法、物件、程式碼塊,如下例項中的value。
(3)因為wait()釋放了鎖,故其他執行緒可以執行本來由sycronized修飾的內容。例如下面例項中的run()方法內列印value值(System.out.println(value);)。
3.例項
如下,我們首先新建自己的執行緒類,覆寫run()方法,新執行緒的作用是判斷傳進來的值是不是”123”,如果是就等待10s,不是就修改傳進來的值並打印出來。
public class MyThread extends Thread {
StringBuilder value;
public MyThread(StringBuilder value) {
this.value = value;
}
@Override
public void run() {
try {
synchronized (value) {
System.out.println(value);
if ((value.toString()).equals("123")) {
System.out.println(getName() + "開始等待;當前時間秒數:" + Calendar.getInstance().get(Calendar.SECOND));
value.wait(10000);// 注意這裡不是說讓value進行wait,而是讓當前執行緒進行wait
} else {
value = value.append("2");
System.out.println("當前執行緒名:" + getName() + ";" + value );
}
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
然後在主函式中新建三個自己定義的執行緒並執行:
public static void main(String[] args) {
// TODO Auto-generated method stub
StringBuilder value = new StringBuilder("123");
MyThread myThread1 = new MyThread(value);
MyThread myThread2 = new MyThread(value);
MyThread myThread3 = new MyThread(value);
myThread1.start();
myThread2.start();
myThread3.start();
}
這個程式的執行結果為:
123
Thread-0開始等待;當前時間秒數:5
123
Thread-2開始等待;當前時間秒數:5
123
Thread-1開始等待;當前時間秒數:5
如果我們把MyThread類的第9行和第18行,也就是sycronized的修飾去掉,就會報“java.lang.IllegalMonitorStateException”異常。
如果我們把MyThread類的第13行的value.wait(10000)語句替換為sleep(10000),則輸出如下:
123
Thread-1開始等待;當前時間秒數:5
123
Thread-0開始等待;當前時間秒數:15
123
Thread-2開始等待;當前時間秒數:25
由輸出的時間秒數可見,使用sleep會使三個執行緒依此執行,一個等待完10s後另一個才會進入sycronized內進行等待。而使用wait,則三個執行緒基本都是一起開始等待的,也就是wait會釋放對value的鎖定,其他執行緒可以執行sycronized程式碼塊中的語句。另外使用sleep並不一定非要同步,這裡是為了驗證sleep不會釋放鎖。