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函数中定义同步方法,也可以解决等待唤醒问题