Java多线程之生产者与消费者
1、仓库
1 package com.cn.donleo.thread.house; 2 3 /** 4 * @author liangd 5 * date 2020-11-02 10:36 6 * code 仓库 7 */ 8 public class StoreHouse { 9 /** 10 * 仓库容纳数量 11 */ 12 public static int count = 10; 13 /** 14 * 判断仓库是否有东西 15 */ 16 public static Boolean isNull =false; 17 public static final Object OBJECT = new Object(); 18 }
2、生产者
1 package com.cn.donleo.thread.house; 2 3 /** 4 * @author liangd 5 * date 2020-11-02 10:40 6 * code 7 */ 8 public class Productor extends Thread { 9 /** 10 * 对于生产者来说,我们需要以下几个步骤: 11 * 判断生产者是否还可以生产,因为规定一天只生产10个,可以则继续,不能则返回 12 * 第一:判断仓库里面是否有还有物品 13 * 第二:如果有,则线程等待,即等待消费者来拿 14 * 第三:如果没有,则生产物品,并提示仓库里面有东西,并呼叫消费者 15 * 生产者的run方法,一直向仓库添加元素 16 */ 17 @Override 18 public void run() { 19 while (true) { 20 //必须要求我们生产者和消费者里面的东西唯一,否则消费者拿到的东西就不是生产者生产的东西, 21 //所以不能用new WareHouse(),来创建对象 22 synchronized (StoreHouse.OBJECT) { 23 if (StoreHouse.count == 0) { 24 break; 25 } else { 26 if (!StoreHouse.isNull) { 27 System.out.println(getName() + "生产者生产产品"); 28 StoreHouse.isNull = true; 29 /* 30 一、notify和notifyAll的区别 31 主要区别:notify和notifyAll之间的关键区别在于notify()只会唤醒一个线程, 32 而notifyAll方法将唤醒所有线程。 33 34 二、何时在Java中使用notify和notifyAll? 35 1、如果所有线程都在等待相同的条件,并且一次只有一个线程可以从条件变为true, 36 则可以使用notify over notifyAll。 37 2、在这种情况下,notify是优于notifyAll 因为唤醒所有这些因为我们知道只有一个线程会受益 38 而所有其他线程将再次等待,所以调用notifyAll方法只是浪费CPU。 39 3、虽然这看起来很合理,但仍有一个警告,即无意中的接收者吞下了关键通知。 40 通过使用notifyAll,我们确保所有收件人都会收到通知 41 42 */ 43 StoreHouse.OBJECT.notifyAll(); 44 } else { 45 try { 46 /* 47 一、notify、 notifyAll、wait属于Object里面的方法 48 二、sleep和wait有什么区别 49 1、Sleep是属于Thread类的静态方法,wait属于Object的方法。 50 2、最主要是sleep方法没有释放锁,而是放弃CPU的调度。而wait方法释放了锁, 51 使得其他线程可以进入同步控制块或者方法。 52 3、wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用, 53 而sleep可以在任何地方使用,synchronized(x){x.notify()//或者wait()} 54 4、sleep必须捕获异常,wait也需要捕获异常,notify和notifyAll不需要捕获异常 55 5、使用wait,notify可以达到线程之间的通信目的 56 */ 57 /* 58 1.使用sleep方法,在毫秒值结束后,线程睡醒进入到Runnable/blocked状态 59 2.使用wait方法,wait方法如果在毫秒值结束后,还没有被notify唤醒,就会自动醒来, 60 线程睡醒进入到Runnable/blocked状态 61 */ 62 StoreHouse.OBJECT.wait(); 63 // StoreHouse.OBJECT.wait(500); 64 } catch (InterruptedException e) { 65 e.printStackTrace(); 66 } 67 } 68 } 69 } 70 } 71 } 72 }
3、消费者
1 package com.cn.donleo.thread.house; 2 3 /** 4 * @author liangd 5 * date 2020-11-02 10:40 6 * code 7 */ 8 public class Consumer extends Thread { 9 /** 10 * 1.while(true) 11 * 2.synchronized () 12 * 3.判断生产者是否已经停止生产了,如果已经停止了,就跳出,如果没有,则可以继续去仓库拿 13 * 4.判断仓库是否有物品,如果有,则直接拿。拿了就需要讲次数减一,然后呼叫生产者生产 14 * 5.如果没有,则等待生产者生产 15 */ 16 @Override 17 public void run() { 18 while (true) { 19 //必须要求我们生产者和消费者里面的东西唯一,否则消费者拿到的东西就不是生产者生产的东西, 20 //所以不能用new WareHouse(),来创建对象 21 synchronized (StoreHouse.OBJECT) { 22 try { 23 //休眠0.5s 24 Thread.sleep(500); 25 } catch (InterruptedException e) { 26 e.printStackTrace(); 27 } 28 if (StoreHouse.count == 0) { 29 break; 30 } else { 31 if (StoreHouse.isNull) { 32 System.out.println(getName() + "消费者可以拿产品了"); 33 StoreHouse.isNull = false; 34 StoreHouse.OBJECT.notifyAll(); 35 StoreHouse.count--; 36 } else { 37 try { 38 StoreHouse.OBJECT.wait(); 39 } catch (InterruptedException e) { 40 e.printStackTrace(); 41 } 42 } 43 } 44 } 45 } 46 } 47 }
4、测试类
1 package com.cn.donleo.thread.house; 2 3 /** 4 * @author liangd 5 * date 2020-11-02 10:56 6 * code 生产者消费者测试类 7 */ 8 public class TestProductorCunsumer { 9 public static void main(String[] args){ 10 //线程1 11 Productor productor = new Productor(); 12 productor.setName("生产者"); 13 //线程2 14 Consumer consumer1 = new Consumer(); 15 consumer1.setName("A消费者"); 16 //线程3 17 Consumer consumer2 = new Consumer(); 18 consumer2.setName("B消费者"); 19 productor.start(); 20 consumer1.start(); 21 consumer2.start(); 22 } 23 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix