1. 程式人生 > >java多執行緒:結合多執行緒交替列印10次abc例項,對wait/notify使用的徹底理解

java多執行緒:結合多執行緒交替列印10次abc例項,對wait/notify使用的徹底理解

有個朋友看點選開啟連結 裡的三個執行緒“A執行緒列印10次A,B執行緒列印10次B,C執行緒列印10次C,要求執行緒同時執行,交替列印10次ABC。” 這個問題的程式碼,有點不太理解,讓我給看下。不理解的原因也很簡單,就是對wait和notify理解不深,遇到複雜點的場景會迷糊。對於併發相關的東西,非常推薦書併發程式設計實戰(童雲蘭譯)。這篇部落格純粹是為了直觀理解而寫,所以講解時用詞不準確,如果是想看一些概念的精確定義,建議看書,不要看這篇。

/**
 * wait用法
 * @author DreamSea 
 * @time 2015.3.9 
 */
package com.multithread.wait;
public class MyThreadPrinter2 implements Runnable {   	  
    private String name;   
    private Object prev;   
    private Object self;     
    private MyThreadPrinter2(String name, Object prev, Object self) {   
        this.name = name;   
        this.prev = prev;   
        this.self = self;   
    }     
    @Override  
    public void run() {   
        int count = 10;   
        while (count > 0) {   
            synchronized (prev) {   // 1 程式碼1 處
                synchronized (self) {   // 2 程式碼2 處
                    System.out.print(name);   
                    count--;                      
                    self.notify();   // 3 程式碼3處
                }   
                try {   
                    prev.wait();   // 4 程式碼4處
                } catch (InterruptedException e) {   
                    e.printStackTrace();   
                }   
            }     
        }   
    }   
  
    public static void main(String[] args) throws Exception {   
        Object a = new Object();   
        Object b = new Object();   
        Object c = new Object();   
        MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a);   
        MyThreadPrinter2 pb = new MyThreadPrinter2("B", a, b);   
        MyThreadPrinter2 pc = new MyThreadPrinter2("C", b, c);             
           
        new Thread(pa).start();
        Thread.sleep(100);  //確保按順序A、B、C執行
        new Thread(pb).start();
        Thread.sleep(100);  
        new Thread(pc).start();   
        Thread.sleep(100);  
        }   
}  

正文:

一些概念:

1 wait會釋放鎖,並使當前執行緒休眠。

2 有一點需要注意的是notify()呼叫後,並不是馬上就釋放物件鎖的,而是在相應的synchronized(){}語句塊執行結束,自動釋放鎖。

結合程式碼理解:

問1: "wait會釋放鎖,並使當前執行緒休眠"的理解

第一次A執行緒先執行,new Thread(pa).start()。在程式碼中1和2處分別擁有prev(c鎖)和self(a鎖)。

對於初學者來說在A執行緒過程中,程式碼中4處要理解到哪些點呢?

第一點,wait會釋放鎖,釋放誰的鎖?因為是prev.wait(),所以釋放的是prev鎖,即c鎖。第二點,使執行緒休眠,哪個執行緒休眠?

是不是說因為是prev.wait(),所以休眠的是prev(c鎖)對應的c執行緒呢?不是,這裡的休眠是當前執行的執行緒休眠,即A執行緒休眠,而不是c執行緒休眠。第三點,如何喚醒A執行緒呢,使用a.notify還是c.notify是不是說當前執行緒休眠了,用當前執行緒喚醒(a.notify)就行了?不是,前面用的是c.wait (即程式碼中的prev.wait,執行時引數prev代指的就是c)使執行緒A休眠。所以這裡仍然需要c.notify喚醒執行緒A。

{2018.5.27補充:

最近想系統的看下併發程式設計相關的東西,更進一步的研究下邊邊角角的小知識。看併發程式設計實戰的時候,不知是中文翻譯的問題,還是圖書作者doug lea段位太高的原因,有些段落讓人讀了不明所以。於是就結合了其他併發書籍交叉閱讀。在翻"java併發程式設計的藝術"時,掃了一眼“等待/通知機制”章節,發現介紹的還不錯,而且也正好和我的這篇部落格主題契合,這裡就摘要一些。轉載自連結:

http://blog.csdn.net/wabiaozia/article/details/79534560

等待/通知的相關方法是任意Java物件都具備的,因為這些方法被定義在所有物件的超類java.lang.Object上
等待/通知機制,是指一個
執行緒A呼叫物件O的wait()方法進入等待狀態,而另一個執行緒B呼叫了物件O的notify()或者notifyAll()方法,執行緒A收到通知後從物件O的wait()方法返回,進而執行後續操作。上述兩個執行緒通過物件O來完成互動,而物件上的wait()和notify/notifyAll()的關係就如同開關訊號一樣,用來完成等待方和通知方之間的互動工作。

}

問2: notify()呼叫後,會馬上就釋放物件鎖

下文中的程式碼3處,notify()呼叫後並不是馬上就釋放物件鎖的,而是在相應的synchronized(){}語句塊執行結束,自動釋放鎖。

問3:小結下A執行緒的執行流程

執行程式碼1和2處,分別是c和a鎖,這點很好理解。程式碼3處釋放a鎖。程式碼4處,釋放c鎖,同時休眠A執行緒,下次需要c.notify() 才能喚醒A執行緒。

有lock鎖,ReentrantLock結合Condition,訊號量Semaphore等。我部落格所有文章連結:http://blog.csdn.net/wabiaozia