Strength is built under a heavy load,I am expecting to pick up all of my loads and travel on.?
?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????—— 24.5.24
章節重點
1.會用wait和notify兩個方法
2.會使用Lock鎖對象
3.會利用Cal1able接口實現多線程
4.會使用線程池完成多線程
等待喚醒案例分析(線程之間的通信)
要求:
????????一個線程生成,一個線程消費,不能連續生產和消費 ——> 等待喚醒機制(生產者,消費者)(線程之間的通信)
方法:
????????void wait():線程等待,等待的過程中線程會釋放鎖,需要被其他線程調用notify方法將其喚醒,重新搶鎖執行
????????void notify():線程喚醒,一次喚醒一個等待線程;如果有多條線程等待,則隨機喚醒一條等待線程? ? ? ? void notifyAll():喚醒所有等待線程
wait和notify方法需要鎖對象調用,所以需要用到同步代碼塊中,而且必須是同一個鎖對象
案例:
????????包子鋪生產和消費的案例,一個線程生產包子,一個線程消費包子,但是不能連續生產,也不能連續消費(需要生產一個消費一個)
JavaBean
package S75ThreadWaitNotify;public class BaoZiPu {// 包子的數目countprivate int count;// 是否有包子flagprivate boolean flag;public BaoZiPu() {}public BaoZiPu(int count, boolean flag) {this.count = count;this.flag = flag;}// getCount改成消費包子,直接輸出包子數量countpublic void getCount() {System.out.println("消費了第"+count+"個包子");}// setCount改造成生產包子,count++public void setCount() {count++;System.out.println("生產了第"+count+"個包子");}public boolean isFlag() {return flag;}public void setFlag(boolean flag) {this.flag = flag;} }
生產線程
package S76ThreadWaitNotify;// 實現Runnable接口 public class Product implements Runnable{private BaoZiPu baoZiPu;public Product(BaoZiPu baoZiPu){this.baoZiPu = baoZiPu;}@Overridepublic void run() {// 定義一個死循環while(true) {try {Thread.sleep(100L);}catch (InterruptedException e){throw new RuntimeException(e);}// 同步代碼塊synchronized (baoZiPu){// 1.判斷flag是否為true,如果是true,證明有包子,生產線程等待if(baoZiPu.isFlag()==true){try{baoZiPu.wait();}catch(InterruptedException e){throw new RuntimeException(e);}}// 2.如果flag為false,則要開始生產baoZiPu.setCount();// 3.改變flag為truebaoZiPu.setFlag(true);// 4.喚醒喚醒生產線程baoZiPu.notify();}}} }
消費線程
package S76ThreadWaitNotify;public class Consumer implements Runnable{private BaoZiPu baoZiPu;public Consumer(BaoZiPu baoZiPu){this.baoZiPu = baoZiPu;}@Overridepublic void run() {while(true) {try {Thread.sleep(100L);}catch (InterruptedException e){throw new RuntimeException(e);}// 同步代碼塊synchronized (baoZiPu){// 1.判斷flag是否為false,如果是false,證明沒有包子,消費線程等待if(baoZiPu.isFlag()==false){// 拋出異常try{baoZiPu.wait();}catch(InterruptedException e){throw new RuntimeException(e);}}// 2.如果flag為true,則要開始消費baoZiPu.getCount();// 3.改變flag為false,消費完了,沒有包子了baoZiPu.setFlag(false);// 4.喚醒消費線程baoZiPu.notify();}}} }
Test
package S75ThreadWaitNotify;public class Demo214Test {public static void main(String[] args) {// 變成同一個對象BaoZiPu baoZiPu = new BaoZiPu();Product product = new Product(baoZiPu);Consumer consumer = new Consumer(baoZiPu);Thread thread1 = new Thread(product);Thread thread2 = new Thread(consumer);thread1.start();thread2.start();} }
運行結果:(先生產線程進行判斷,若flag為false,則wait等待,讓出鎖讓consume消費現場先執行,若消費線程的包子數量為0,則喚醒生產線程,consume等待)
也可以同步方法實現等待喚醒,直接在BaoZiPu函數中定義同步方法,也可以解決等待喚醒問題