java基礎知識回顧之java Thread類學習(七)--java多執行緒通訊等待喚醒機制(wait和notify,notifyAll)...

weixin_34262482發表於2014-08-09

1.wait和notify,notifyAll

  • wait和notify,notifyAll是Object類方法,因為等待和喚醒必須是同一個鎖,不可以對不同鎖中的執行緒進行喚醒,而鎖可以是任意物件,所以可以被任意物件呼叫的方法,定義在Object基類中。
  • wait()方法:對此物件呼叫wait方法導致本執行緒放棄物件鎖,讓執行緒處於凍結狀態,進入等待執行緒的執行緒池當中。wait是指已經進入同步鎖的執行緒,讓自己暫時讓出同步鎖,以便使其他正在等待此鎖的執行緒可以進入同步鎖並執行,只有其它執行緒呼叫notify方法或者notifyAll方法後,才能喚醒執行緒池中等待的執行緒。
  • notify()方法:喚醒執行緒池中的任意一個執行緒。
  • notifyAll方法:喚醒執行緒池中的所有執行緒。

2.執行緒間通訊多個執行緒操作同一個資源,但是操作的動作不同,任務不同。

3.等待喚醒機制:操作共享資料的不同動作,一個存入,一個取出;當輸入一個的時候,另一個要取出。先讓輸入執行緒等待,等輸出執行緒取出後,再喚醒輸入執行緒。

下面看一個例子:需求是要求兩個執行緒操作Resource資源類中的成員變數name,sex,要求一個執行緒往共享資源類中存入一個姓名和一個姓別,即存入一個資源物件,另一個執行緒就取出資源類中的物件。即存入一個,就要取出,資源類中物件為空的時候,就再存入一個。這個例子可以用等待喚醒機制解決。

思路:這裡線上程程式碼裡面設計一個姓名為peter,性別為man;另一個姓名為“李明”,性別為“男”。通過模2進行切換。輸入執行緒選擇操作這連個物件。

 

class Res{
    String name;
    String sex;
    boolean flag = false;
}

class Input implements Runnable{
    Object obj = new Object();
    private Res r ;

    public Input(Res r){//通過構造方法初始化資源,把Res傳遞進來,一構造物件,資源被初始化
        this.r = r;
    }

    public void run(){
        int x= 0;
        while(true){
            synchronized(r){//同步程式碼塊,鎖為r
                if(r.flag){//如果資源裡面有一個姓名和名字了,input執行緒就凍結,釋放執行權,釋放執行資格,釋放鎖
                    try {
                        r.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                    if(x == 0){//切換x,通過模2進行切換
                        r.name="peter";
                        r.sex="man";
                    }else{
                        r.name="李明";
                        r.sex="男男男男";
                    }
                    x = (x+1)%2;//取模運算,模2=0,取名字為Mike,性別為man,不等於0,則取小紅,女女女女
                    r.flag = true;//當存入一個,標誌變為true,輸入執行緒進入等待,處於凍結狀態,等待輸出執行緒輸出
                    r.notify();//喚醒執行緒池中的其它執行緒,喚醒第一個等待的輸出執行緒
            }
        }
    }
    
}
class OutPut implements Runnable{
    Object obj = new Object();
    private Res r;
    public OutPut(Res r){
        this.r  = r;
    }
    public void run() {
        
        while(true){
            synchronized(r){
                if(!r.flag)
                    try {
                        r.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    //如果r.flag=true,說明資源Res裡面有一個東西,輸出裡面名字和性別
                    System.out.println(r.name+ "......"+r.sex);
                    r.flag=false;//當輸出一個,標誌改為false,這時輸出執行緒進入執行緒池進行等待,直到被喚醒
                    r.notify();//喚醒輸入執行緒,導致當前執行緒等待
            }
        }
    }
    
}
public class ThreadorThreadSpeak {

    /**
     * @param args
     */
    public static void main(String[] args) {
        //建立資源
        Res r = new Res();//比喻為煤資源
        //建立任務
        Input in = new Input(r);
        OutPut out = new OutPut(r);
        //建立執行緒
        Thread t1 = new Thread(in);//輸入執行緒
        Thread t2 = new Thread(out);//輸出執行緒
        //開啟執行緒
        t1.start();
        t2.start();
    }

}

 

優化上面的程式碼,把同步程式碼塊中的程式碼封裝成同步函式

class Resource
{
    private String name;
    private String sex;
    private boolean flag = false;

    public synchronized void set(String name,String sex)
    {
        if(flag)
            try{this.wait();}catch(InterruptedException e){}
        this.name = name;
        this.sex = sex;
        flag = true;
        this.notify();
    }

    public synchronized void out()
    {
        if(!flag)
            try{this.wait();}catch(InterruptedException e){}
        System.out.println(name+"...+...."+sex);
        flag = false;
        notify();
    }
}


//輸入
class Input implements Runnable
{
    Resource r ;
    Input(Resource r)
    {
        this.r = r;
    }
    public void run()
    {
        int x = 0;
        while(true)
        {
       //取2模進行切換
if(x==0) { r.set("peter","nan"); } else { r.set("李明","男男男男"); } x = (x+1)%2; } } } //輸出 class Output implements Runnable { Resource r; Output(Resource r) { this.r = r; } public void run() { while(true) { r.out(); } } } class ResourceDemo3 { public static void main(String[] args) { //建立資源。 Resource r = new Resource(); //建立任務。 Input in = new Input(r); Output out = new Output(r); //建立執行緒,執行路徑。 Thread t1 = new Thread(in); Thread t2 = new Thread(out); //開啟執行緒 t1.start(); t2.start(); } }

輸出:

peter......man
李明......男男男男
peter......man
李明......男男男男
peter......man

 

 

相關文章