天天看點

精通java并發-wait,notify和notifyAll的總結(含案例)wait,notify和notifyAll

目前CSDN,部落格園,簡書同步發表中,更多精彩歡迎通路我的gitee pages

wait,notify和notifyAll

總結

  • 在調用wait方法時,線程必須要持有被調用對象的鎖,當調用wait方法後,線程就會釋放掉該對象的鎖(monitor)
  • 在調用Thread類的sleep方法時,線程是不會釋放掉對象的鎖的
  1. 當調用wait時,首先需要確定調用了wait方法的線程已經持有了對象的鎖
  2. 當調用wait後,該線程就會釋放掉這個對象的鎖,然後進入到等待狀态(wait set)
  3. 當線程調用了wait後進入到等待狀态時,它就可以等待其他線程調用相同對象的notify或notifyAll方法來使得自己被喚醒
  4. 一旦這個線程被其他線程喚醒後,該線程就會與其他線程一同開始競争這個對象的鎖(公平競争);隻有當該線程擷取到了這個對象的鎖後,線程才會繼續往下執行
  5. 調用wait方法的代碼片段需要放在一個synchronized塊或是synchronized方法中,這樣才可以確定線程在調用wait方法前已經擷取到了對象的鎖
  6. 當調用對象的notify方法時,它會随機喚醒該對象等待集合(wait set)中的任意一個線程,當某個線程被喚醒後,它就會與其他線程一同競争對象的鎖
  7. 當調用對象的notifyAll方法時,它會喚醒該對象等待集合(wait set)中的所有線程,這些線程被喚醒後,又會開始競争對象的鎖
  8. 在某一時刻,隻有唯一一個線程可以擁有對象的鎖

案例

編寫一個多線程程式,實作這樣一個目标:
  1. 存在一個對象,該對象有一個int類型的成員變量counter,該成員變量的初始值為0.
  2. 建立兩個線程,其中一個線程對該對象的成員變量counter增1,另一個線程對該對象的成員變量減1.
  3. 輸出該對象成員變量counter每次變化後的值.
  4. 最終輸出結果應為:101010101010…
  • 建立一個普通類MyObject,有成員變量counter,有一個使counter++的方法和一個使counter–的方法.
public class MyObject {

    private int counter;

    public synchronized void increase() {
        while (counter != 0) {
            try {
                wait();
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
        counter++;
        System.out.print(counter);
        notify();
    }

    public synchronized void decrease() {
        while (counter == 0) {
            try {
                wait();
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
        counter--;
        System.out.print(counter);
        notify();
    }
}
           
  • 建立一個調用MyObject的increase方法的線程類IncreaseThread
public class IncreaseThread extends Thread {

    private MyObject myObject;

    public IncreaseThread(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run() {
        for (int i = 0; i < 30; ++i) {
            try {
                Thread.sleep((long)(Math.random() * 1000));
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }

            myObject.increase();
        }
    }
}
           
  • 建立一個調用MyObject的decrease方法的線程類DecreaseThread
public class DecreaseThread extends Thread {

    private MyObject myObject;

    public DecreaseThread(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run() {
        for (int i = 0; i < 30; ++i) {
            try {
                Thread.sleep((long)(Math.random() * 1000));
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            myObject.decrease();
        }
    }
}
           
  • 建立一個含main方法的Client類
public class Client {

    public static void main(String[] args) {
        MyObject myObject = new MyObject();

        Thread increaseThread = new IncreaseThread(myObject);
        Thread increaseThread2 = new IncreaseThread(myObject);
        Thread decreaseThread = new DecreaseThread(myObject);
        Thread decreaseThread2 = new DecreaseThread(myObject);

        increaseThread.start();
        increaseThread2.start();
        decreaseThread.start();
        decreaseThread2.start();
    }
}
           
  • 執行結果
精通java并發-wait,notify和notifyAll的總結(含案例)wait,notify和notifyAll