1.wait(),notify()與notifyAll():java
wait(),notify()與notifyAll方法是java.lang.Object類的方法,因此這些方法不能被子類重寫,Object類是全部類的超類。
ide
void wait() | 致使線程進入等待狀態,直到它被其餘線程經過notify()或者notifyAll喚醒 |
void wait(long t) //毫秒 |
在其餘線程調用此對象的 notify() 方法或notifyAll()方法,或者超過指定的時間量前,致使當前線程等待。 |
void wait(long t, int n) |
a. 其餘線程經過調用
// wait(0) 與wait(0,0)相同this |
void notify() |
隨機選擇一個在該對象上調用wait方法的線程,解除其阻塞狀態。 (單個線程) |
void notifyAll() | 喚醒在此對象監視器上等待的全部線程。spa |
wait(),notify(),notifyAll()必須寫在同步方法中(synchronized方法內部或者synchronized塊內部),這是由於這幾個方法要求當前正在運行Object.wait()方法的線程擁有Object的對象鎖,即當前線程必須擁有此對象監視器,不然將會拋出IllegalMonitorStateException(若是當前線程不是此對象監視器的全部者)
。即便你確實知道當前上下文線程確實擁有了對象鎖,也不能將Object.wait()這樣的語句寫在當前上下文中。線程
wait():釋放佔有的對象鎖,線程進入等待池,釋放cpu,而其餘正在等待的線程便可搶佔此鎖,得到鎖的線程便可運行程序。而sleep()不一樣的是,線程調用此方法後,會休眠一段時間,休眠期間,會暫時釋放cpu,但並不釋放對象鎖。也就是說,在休眠期間,其餘線程依然沒法進入此代碼內部。休眠結束,線程從新得到cpu,執行代碼。wait()和sleep()最大的不一樣在於wait()會釋放對象鎖,而sleep()不會!code
notify(): 該方法會喚醒由於調用對象的wait()而等待的線程,其實就是對對象鎖的喚醒,從而使得wait()的線程能夠有機會獲取對象鎖。調用notify()後,並不會當即釋放鎖,而是繼續執行當前代碼,直到synchronized中的代碼所有執行完畢,纔會釋放對象鎖。JVM則會在等待的線程中調度一個線程去得到對象鎖,執行代碼。須要注意的是,wait()和notify()必須在synchronized代碼塊中調用。notifyAll()則是喚醒全部等待的線程。orm
2.簡單的生產者消費者例子:對象
//首先設定一個存放產品的緩衝區: public class CollectionBuffer { //緩衝區最大存儲量 private final int MAX_SIZE = 100; //緩衝區存儲量載體 LinkedList<Object> list = new LinkedList<Object>(); // 此實現並不是同步 public LinkedList<Object> getList() { return list; } public void setList(LinkedList<Object> list) { this.list = list; } public int getMAX_SIZE() { return MAX_SIZE; } //生產產品 num 個 public void produce( int num ){ //同步代碼塊 synchronized(list){ //若是倉庫剩餘量不足,即生產產品可能過多 while( list.size() + num > MAX_SIZE ){ System.out.println("即將生產產品數量爲: " + num +" 但已有庫存量爲: "+ list.size() +" 暫時不能再進行生產任務<產品數量會大於最大庫存量>"); try { //等會再生產,陷入等待狀態(阻塞) 會釋放對象鎖,而sleep不會 list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //若是知足條件,則生產產品: for( int i=1;i<=num;i++){ list.add( new Object() ); } System.out.println("已經生產產品數量爲:" + num + " 現生產後新的庫存量爲:" + list.size() ); list.notifyAll(); } } //消費產品 num 個 public void consume( int num ){ // 同步代碼塊 synchronized(list){ while( list.size() < num ){ System.out.println("想要消費產品數量爲: " + num +" 但當前庫存產品量爲: " + list.size() +" 暫時還不能消費<庫存量小於消費量>"); try { // 不知足消費條件,等待(阻塞) list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //若是知足消費條件, 即庫存量足夠消費者消費 消費量小於庫存量。 for( int i=1;i<=num;i++){ list.remove(); } System.out.println("已經消費產品數量爲: " + num + " 現消費後新的庫存量爲: " + list.size() ); list.notifyAll(); } } } // 生產者: public class Producer extends Thread { // 每次生產的產品量 private int num; //存放的倉庫(緩衝容器) private CollectionBuffer collectionBuffer; // 構造函數 設置存儲緩衝區倉庫 public Producer(CollectionBuffer collectionBuffer){ this.collectionBuffer = collectionBuffer; } @Override public void run() { // 調用倉庫緩衝區CollectionBuffer的生產函數 collectionBuffer.produce(num); } public int getNum() { return num; } public void setNum(int num) { this.num = num; } public CollectionBuffer getCollectionBuffer() { return collectionBuffer; } public void setCollectionBuffer(CollectionBuffer collectionBuffer) { this.collectionBuffer = collectionBuffer; } } //消費者: public class Consumer extends Thread{ //每次要消費的產品量: private int num; //消費產品的緩衝倉庫區 private CollectionBuffer collectionBuffer; //構造函數 指定消費商品的緩衝區 public Consumer(CollectionBuffer collectionBuffer){ this.collectionBuffer = collectionBuffer; } @Override public void run() { //調用緩衝區中的消費產品的函數,指定消費量 collectionBuffer.consume(num); } public int getNum() { return num; } public void setNum(int num) { this.num = num; } public CollectionBuffer getCollectionBuffer() { return collectionBuffer; } public void setCollectionBuffer(CollectionBuffer collectionBuffer) { this.collectionBuffer = collectionBuffer; } } // 測試類: public class TestPC { public static void main(String[] args) throws InterruptedException { //建立倉庫緩衝區對象 CollectionBuffer cb = new CollectionBuffer(); //建立多個生產者對象 Producer p1 = new Producer(cb); Producer p2 = new Producer(cb); Producer p3 = new Producer(cb); Producer p4 = new Producer(cb); Producer p5 = new Producer(cb); Producer p6 = new Producer(cb); //建立多個消費者對象 Consumer c1 = new Consumer(cb); Consumer c2 = new Consumer(cb); Consumer c3 = new Consumer(cb); Consumer c4 = new Consumer(cb); Consumer c5 = new Consumer(cb); Consumer c6 = new Consumer(cb); //開始設置生產者生產產品數量 p1.setNum(10); p2.setNum(20); p3.setNum(30); p4.setNum(60); p5.setNum(80); p6.setNum(90); //開始讓消費者消費產品數量 c1.setNum( 80 ); c2.setNum( 60 ); c3.setNum( 50 ); c4.setNum( 35 ); c5.setNum( 20 ); c6.setNum( 10 ); // 讓線程開始執行 c1.start(); c2.start(); p1.start(); p2.start(); c6.start(); p4.start(); c3.start(); p3.start(); p5.start(); c4.start(); p6.start(); c5.start(); } }