1. 程式人生 > >java的wait()方法使用注意事項

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不會釋放鎖。