1. 程式人生 > 其它 >java基礎知識回顧之java Thread類學習(三)--java多執行緒通訊等待喚醒機制(wait和notify,notifyAll)

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

1.wait和notify,notifyAll

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

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

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

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

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

java基礎知識回顧之java Thread類學習(八)--java.util.concurrent.locks(JDK1.5)與synchronized異同講解

看API文件介紹幾個方法:

JDK1.5中提供了多執行緒的升級解決方案:

特點:1.將同步synchronized顯示的替換成Lock
2.介面Condition:Condition替代了Object監視器方法(wait、notify、notifyAll),分別替換成了await(),signal() (喚醒一個等待線     程),signalAll() 喚醒多個執行緒。一個鎖可以繫結多個condition物件,可以對應好幾組wait,notify,notifyAll動作。

java.util.concurrent.locks介面
* Lock介面下面的方法
* void lock():獲取鎖,如果鎖不可用,出於執行緒排程目的,將禁用當前執行緒,並且在獲得鎖之前,該執行緒將一直處於休眠狀態。
* boolean tryLock():如果獲得了鎖,返回true。如果別的執行緒正在持有鎖,返回false
* boolean tryLock(long time,//等待多長時間獲得鎖
TimeUnit unit)
throws InterruptedException:
如果獲取到鎖,立即返回true,如果別的執行緒正在持有鎖,會等待引數給定的時間,如果在這段時間內獲得了鎖就返回true,如果等待超時,返 回false。

locks的實現類:
java.lang.Object
-->java.util.concurrent.locks.ReentrantLock類一個可重入的互斥鎖 Lock,替代synchronized,比synchronized有更強大的功能
-->Java.util.concurrent.locks.ReadWriteLock 提供了一對可供讀寫併發的鎖。

使用新的鎖完成生產者消費者模型:

程式碼如下:

倉庫類(資源)

class ResourceNew{
    private String name;
    private boolean flag = false;
    private int count=1;
    
    private final Lock lock = new ReentrantLock();//將同步synchronized顯示的替換成Lock
    private Condition condition_cusumer = lock.newCondition();//同一個鎖上可以繫結多個相關的Condition
    private Condition conditon_producer = lock.newCondition();
    
    public  void set(String name) throws InterruptedException{
        try{
            lock.lock();//顯示的
            while(flag){
                conditon_producer.await();//生產者等待t1,t2
            }
            this.name = name+"---"+count++;
            System.out.println(Thread.currentThread().getName()+"...生產者..."+this.name);
            this.flag = true;
//condition.signalAll();//喚醒本方和喚醒對方
            condition_cusumer.signal();//喚醒某個消費者
        }finally{
            lock.unlock();//每個執行緒進入鎖必須要執行的操作,最終要釋放鎖
        }
    }
    
    public  void out() throws InterruptedException{
        try{
            lock.lock();
            while(!flag){
                condition_cusumer.await();//消費者等待
            }
            System.out.println(Thread.currentThread().getName()+".消費者."+this.name);
            this.flag = false;
            conditon_producer.signalAll();//喚醒生產者
        }finally{
            lock.unlock();
        }
    }
    
}

生產者:

/**
 * 
 * @author Administrator
 * 生產者負責生產,操作同一個資源,但是是生產動作
 *
 */
class producerNew implements Runnable{
    private ResourceNew res;
    public producerNew(ResourceNew res){
        this.res = res;
    }
    public void run() {
        while(true){
            try {
                res.set("..商品..");
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}
/**
 * 
 * @author Administrator
 * 消費者負責消費生產者提供的產品,操作的同一個資源,但是是消費動作
 *
 */
class CusumerNew implements Runnable{
    private ResourceNew res;
    public CusumerNew(ResourceNew res){
        this.res = res;
    }
    public void run() {
        while(true){
            try {
                res.out();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

消費者:

/**
 * 
 * @author Administrator
 * 消費者負責消費生產者提供的產品,操作的同一個資源,但是是消費動作
 *
 */
class CusumerNew implements Runnable{
    private ResourceNew res;
    public CusumerNew(ResourceNew res){
        this.res = res;
    }
    public void run() {
        while(true){
            try {
                res.out();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

synchronized和java.util.concurrent.locks.Lock的異同 :
* 相同點:Lock能完成synchronized所實現的所有功能。
* 不同點:1.Lock比Synchonized更精確的執行緒鎖語義和更好的效能。(Synchonized是獨佔鎖,效能不高,而Lock是藉助於JNI,效能更高)
* 2.Lock必須手動釋放鎖,在finally裡面呼叫unlock()方法釋放鎖,而synchronized會自動釋放鎖。