北京网站设计制作,网页制作入门与进阶,实惠福步外贸论坛,网络营销具有很强的什么特征生产者和消费者
概述#xff1a;
生产者消费者问题#xff0c;实际上主要是包含了两类线程#xff1a;
生产者线程用于生产数据消费者线程用于消费数据
生产者和消费者之间通常会采用一个共享的数据区域#xff0c;这样就可以将生产者和消费者进行解耦#xff0c;
两…生产者和消费者
概述
生产者消费者问题实际上主要是包含了两类线程
生产者线程用于生产数据消费者线程用于消费数据
生产者和消费者之间通常会采用一个共享的数据区域这样就可以将生产者和消费者进行解耦
两者都不需要互相关注对方的
方法
Object类的等待和唤醒方法
方法名说明void wait()导致当前线程等待直到另一个线程调用该对象的 notify()方法或 notifyAll()方法void notify()唤醒正在等待对象监视器的单个线程void notifyAll()唤醒正在等待对象监视器的所有线程
案例需求 桌子类(Desk)定义表示双吉芝士汉堡数量的变量,定义锁对象变量,定义标记桌子上有无双吉芝士汉堡的变量 生产者类(Cooker)实现Runnable接口重写run()方法设置线程任务 1.判断是否有双吉芝士汉堡,决定当前线程是否执行 2.如果有双吉芝士汉堡,就进入等待状态,如果没有双吉芝士汉堡继续执行,生产双吉芝士汉堡 3.生产双吉芝士汉堡之后,更新桌子上双吉芝士汉堡状态,唤醒消费者消费双吉芝士汉堡 消费者类(Foodie)实现Runnable接口重写run()方法设置线程任务 1.判断是否有双吉芝士汉堡,决定当前线程是否执行 2.如果没有双吉芝士汉堡,就进入等待状态,如果有双吉芝士汉堡,就消费双吉芝士汉堡 3.消费双吉芝士汉堡后,更新桌子上双吉芝士汉堡状态,唤醒生产者生产双吉芝士汉堡 测试类(Demo)里面有main方法main方法中的代码步骤如下 创建生产者线程和消费者线程对象 分别开启两个线程 /*** Authorkkoneone11* nameCooker* Date2023/8/27 18:55*/
public class Cooker extends Thread{private Desk desk;public Cooker(Desk desk){this.desk desk;}// 生产者步骤
// 1判断桌子上是否有双吉芝士汉堡
// 如果有就等待如果没有才生产。
// 2把双吉芝士汉堡放在桌子上。
// 3叫醒等待的消费者开吃。Overridepublic void run(){while(true){synchronized (desk.getLock()){if(desk.getCount() 0){break;}else {if(!desk.isFlag()){System.out.println(厨师正在制作双吉芝士汉堡);//生产双层吉士desk.setFlag(true);//叫醒麦门弟子干饭desk.getLock().notifyAll();}else{try{desk.getLock().wait();}catch (Exception e){e.printStackTrace();}}}}}}
}public class Foodie extends Thread{private Desk desk;public Foodie(Desk desk){this.desk desk;}// 1判断桌子上是否有双吉芝士汉堡。
// 2如果没有就等待。
// 3如果有就开吃
// 4吃完之后桌子上的双吉芝士汉堡就没有了
// 叫醒等待的生产者继续生产
// 双吉芝士汉堡的总数量减一Overridepublic void run(){while(true){synchronized (desk.getLock()){if(desk.getCount() 0){break;}else {if(desk.isFlag()){//有双层吉士System.out.println(麦门弟子疯狂炫吧);desk.setFlag(false);desk.getLock().notifyAll();desk.setCount(desk.getCount() -1);}else{//没有双层吉士 等待//使用什么对象当做锁,那么就必须用这个对象去调用等待和唤醒的方法.try {desk.getLock().wait();}catch (Exception e){e.printStackTrace();}}}}}}
}public class Demo {public static void main(String[] args) {Desk desk new Desk();Foodie f new Foodie(desk);Cooker c new Cooker(desk);f.start();c.start();}
}
阻塞队列
阻塞队列常用于生产者和消费者的场景生产者是往队列里添加元素的线程消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器而消费者也只从容器里拿元素
阻塞队列继承结构 常见BlockingQueue的实现类:
ArrayBlockingQueue: 底层是数组,有界LinkedBlockingQueue: 底层是链表,无界.但不是真正的无界,最大为int的最大值
方法 实例
public class Demo {public static void main(String[] args) throws Exception {// 创建阻塞队列的对象,容量为 1ArrayBlockingQueueString arrayBlockingQueue new ArrayBlockingQueue(1);// 存储元素arrayBlockingQueue.put(双层吉士);// 取元素System.out.println(arrayBlockingQueue.take());System.out.println(arrayBlockingQueue.take()); // 取不到会阻塞System.out.println(程序结束了);}
}
案例需求优化
不再需要Desk这个类改用阻塞队列
public class Cooker extends Thread{private ArrayBlockingQueueString bd;public Cooker(ArrayBlockingQueueString bd) {this.bd bd;}
// 生产者步骤
// 1判断桌子上是否有汉堡包
// 如果有就等待如果没有才生产。
// 2把汉堡包放在桌子上。
// 3叫醒等待的消费者开吃。Overridepublic void run() {while (true) {try {bd.put(汉堡包);System.out.println(厨师放入一个汉堡包);} catch (InterruptedException e) {e.printStackTrace();}}}
}public class Foodie extends Thread{private ArrayBlockingQueueString bd;public Foodie(ArrayBlockingQueueString bd) {this.bd bd;}Overridepublic void run() {
// 1判断桌子上是否有汉堡包。
// 2如果没有就等待。
// 3如果有就开吃
// 4吃完之后桌子上的汉堡包就没有了
// 叫醒等待的生产者继续生产
// 汉堡包的总数量减一while (true) {try {String take bd.take();System.out.println(吃货将 take 拿出来吃了);} catch (InterruptedException e) {e.printStackTrace();}}}}public class Demo {public static void main(String[] args) {ArrayBlockingQueueString bd new ArrayBlockingQueue(1);Foodie f new Foodie(bd);Cooker c new Cooker(bd);f.start();c.start();}
}