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