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 { // 包子的数目count private int count; // 是否有包子flag private boolean flag; public BaoZiPu() { } public BaoZiPu(int count, boolean flag) { this.count = count; this.flag = flag; } // getCount改成消费包子,直接输出包子数量count public 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; } @Override public 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为true baoZiPu.setFlag(true); // 4.唤醒唤醒生产线程 baoZiPu.notify(); } } } }
消费线程
package S76ThreadWaitNotify; public class Consumer implements Runnable{ private BaoZiPu baoZiPu; public Consumer(BaoZiPu baoZiPu){ this.baoZiPu = baoZiPu; } @Override public 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函数中定义同步方法,也可以解决等待唤醒问题