生产者消费者问题
来源:互联网 发布:node.js能实现什么 编辑:程序博客网 时间:2024/05/22 03:43
生产者和消费者问题是java多线程中的等待唤醒机制的经典案例。
下面通过几个例子,循序渐进得了解这个问题。
1.单生产者和单消费者
1 class Res 2 { 3 private String name; 4 private int count=0; 5 private boolean flag=false;//用来标志资源是否为空 6 public Res(String name) 7 { 8 this.name=name; 9 } 10 //为其他类提供实现资源存放的方法 11 public synchronized void set() 12 { 13 //如果资源内容是满的 14 //此时执行的线程,即生产者线程等待 15 if(flag) 16 { try 17 { 18 this.wait(); 19 } 20 catch (Exception e) 21 { 22 System.out.println("出错了"); 23 } 24 } 25 //否则,资源内容为空 26 //新生产一个产品 27 count++; 28 System.out.println("生产者生产了"+name+count); 29 //修改标志 30 flag=true; 31 //唤醒在此对象监视器上等待的某个线程,即消费者线程 32 //第一次执行时,没有等待线程,为空唤醒 33 this.notify(); 34 } 35 36 //为其他类提供资源提取的方法 37 public synchronized void out() 38 { 39 //如果资源内容是空的 40 //此时执行的线程,即消费者线程等待 41 if(!flag) 42 { try 43 { 44 this.wait(); 45 } 46 catch (Exception e) 47 { 48 System.out.println("出错了"); 49 } 50 } 51 //否则,资源内容存在 52 //则消费该产品 53 System.out.println("消费者消费了~~~~~~~~~"+name+count); 54 //修改标志 55 flag=false; 56 //唤醒在此对象监视器上等待的某个线程,即生产者线程 57 this.notify(); 58 } 59 } 60 class Producer1 implements Runnable 61 { 62 Res r; 63 public Producer1(Res r) 64 { 65 this.r=r; 66 } 67 68 //实现run方法 69 public void run() 70 { 71 72 while(true) 73 { 74 r.set(); 75 } 76 } 77 78 } 79 class Customer1 implements Runnable 80 { 81 Res r; 82 public Customer1(Res r) 83 { 84 this.r=r; 85 } 86 87 //实现run方法 88 public void run() 89 { 90 while(true) 91 { 92 r.out(); 93 } 94 } 95 } 96 public class ProducerAndCustomerDemo1 97 { 98 public static void main(String[] args) 99 {100 //建立资源对象101 Res r=new Res("冰淇淋");102 //创建生产者103 Producer1 pro=new Producer1(r);104 //创建消费者105 Customer1 con=new Customer1(r);106 107 //建立线程108 Thread t1=new Thread(pro);109 Thread t2=new Thread(con);110 //开启线程111 t1.start();112 t2.start();113 114 }115 }
运行如下:
2.多生产者和多消费者问题
多生产者和多消费者的情况,如果仍然按照上述写法来写,会发生两种错误:
第一种,输出表现是某个产品被消费了多次或者某个产品没有被消费。
产生原因是,线程被唤醒后接着往下执行,没有再判断flag标记。
解决办法:把if语句,改为while循环。
这时,又会产生第二种错误,死锁。
输出表现:程序自行停止。
产生原因:线程进行唤醒动作时,唤醒了本类线程(例如,消费者线程唤醒了消费者线程),
没能达到唤醒对方的效果(例如,消费者线程应该唤醒生产者线程),而本类线程在进行标志位判断后
,也进入了等待状态,最终致使所有线程都在等待状态,程序停止。
解决办法:把notify语句改为notifyAll,确保线程每次执行唤醒动作时,都能达到唤醒对方的效果。
1 class Res 2 { 3 private String name; 4 private int count=0; 5 private boolean flag=false; 6 public Res(String name) 7 { 8 this.name=name; 9 } 10 11 public synchronized void set() 12 { 13 //while循环判断标志位 14 while(flag) 15 { try 16 { 17 this.wait(); 18 } 19 catch (Exception e) 20 { 21 System.out.println("出错了"); 22 } 23 } 24 25 count++; 26 System.out.println("生产者"+Thread.currentThread().getName()+"生产了"+name+count); 27 flag=true; 28 //唤醒在此对象监视器上等待的所有线程 29 this.notifyAll(); 30 } 31 32 public synchronized void out() 33 { 34 //while循环判断标志位 35 while(!flag) 36 { try 37 { 38 this.wait(); 39 } 40 catch (Exception e) 41 { 42 System.out.println("出错了"); 43 } 44 } 45 System.out.println("消费者"+Thread.currentThread().getName()+"消费了~~~~~~~~~"+name+count); 46 flag=false; 47 //唤醒在此对象监视器上等待的所有线程 48 this.notifyAll(); 49 } 50 } 51 class Producer1 implements Runnable 52 { 53 Res r; 54 public Producer1(Res r) 55 { 56 this.r=r; 57 } 58 59 public void run() 60 { 61 62 while(true) 63 { 64 r.set(); 65 } 66 } 67 68 } 69 class Customer1 implements Runnable 70 { 71 Res r; 72 public Customer1(Res r) 73 { 74 this.r=r; 75 } 76 77 public void run() 78 { 79 while(true) 80 { 81 r.out(); 82 } 83 } 84 } 85 public class ProducerAndCustomerDemo2 86 { 87 public static void main(String[] args) 88 { 89 //建立资源对象 90 Res r=new Res("冰淇淋"); 91 //创建生产者 92 Producer1 pro=new Producer1(r); 93 //创建消费者 94 Customer1 con=new Customer1(r); 95 96 //建立线程 97 Thread t0=new Thread(pro); 98 Thread t1=new Thread(pro); 99 Thread t2=new Thread(con);100 Thread t3=new Thread(con);101 //开启线程102 t0.start();103 t1.start();104 t2.start();105 t3.start();106 107 }108 }
运行如下:
3.多生产者和多消费者问题(JDK1.5的新特性)
两个代替:
JDK1.5的新特性
用Lock接口的实现类,封装锁对象,显式完成申请锁和释放锁的动作,以此代替synchronized同步方法的使用;
Lock实现类的锁对象,最大的好处是,一个锁可以有多个监视器(即Condition对象,而同步代码块的锁只能有一个监视器),
这样就可以分别为生产者和消费者建立不同的监视器,实现只唤醒对方的操作,用指定监视器的singal方法代替了notifyAll方法。
1 import java.util.concurrent.locks.*; 2 class Rec 3 { 4 private String name; 5 private int count=0; 6 private boolean flag=false; 7 //建立锁对象 8 Lock lock=new ReentrantLock(); 9 //得到该锁对象的两个监视器 10 //分别用于生产者和消费者 11 Condition producer_con=lock.newCondition(); 12 Condition customer_con=lock.newCondition(); 13 14 public Rec(String name) 15 { 16 this.name=name; 17 } 18 public void set() 19 { 20 //获取锁 21 lock.lock(); 22 try 23 { 24 while(flag) 25 try 26 { 27 //调用Condition对象的await方法 28 producer_con.await(); 29 } 30 catch (Exception e) 31 { 32 System.out.println("有错误"); 33 } 34 count++; 35 System.out.println(Thread.currentThread().getName()+"生产者~~JDK1.5~~,生产出了"+name+count); 36 37 flag=true; 38 //用消费者线程的监视器唤醒消费者 39 customer_con.signal(); 40 } 41 /*加入try finally结构 42 原因:如果try代码块中出现异常,释放锁的动作就不会被执行 43 因此把释放锁动作放在finally中,确保其执行。 44 45 */ 46 finally 47 { 48 //释放锁 49 lock.unlock(); 50 } 51 } 52 53 public void out() 54 { 55 //获取锁 56 lock.lock(); 57 try 58 { 59 while(!flag) 60 try 61 { 62 customer_con.await(); 63 } 64 catch (Exception e) 65 { 66 System.out.println("有错误"); 67 68 } 69 70 System.out.println(Thread.currentThread().getName()+"消费者~~~~~~~~~JDK1.5~~~~~~~~~~吃掉了"+name+count); 71 flag=false; 72 //用生产者线程的监视器唤醒生产者 73 producer_con.signal(); 74 } 75 finally 76 { 77 //释放锁 78 lock.unlock(); 79 } 80 81 82 } 83 84 85 } 86 class Producer implements Runnable 87 { 88 Rec r; 89 public Producer(Rec r) 90 { 91 this.r=r; 92 } 93 94 public void run() 95 { 96 while(true) 97 { 98 r.set(); 99 }100 }101 }102 class Customer implements Runnable103 {104 Rec r;105 public Customer(Rec r)106 {107 this.r=r;108 }109 110 public void run()111 {112 while(true)113 {114 r.out();115 }116 }117 }118 public class ProAndConLockSolution119 {120 public static void main(String[] args) 121 {122 Rec r=new Rec("北京烤鸭");123 Producer pro1=new Producer(r);124 Producer pro2=new Producer(r);125 Customer con1=new Customer(r);126 Customer con2=new Customer(r);127 128 Thread t0=new Thread(pro1);129 Thread t1=new Thread(pro2);130 Thread t2=new Thread(con1);131 Thread t3=new Thread(con2);132 133 t0.start();134 t1.start();135 t2.start();136 t3.start();137 138 139 }140 }
0 0
- 生产者-消费者问题
- 生产者-消费者问题
- 生产者-消费者问题
- 操作系统:生产者-消费者问题
- 生产者与消费者问题
- 生产者-消费者问题
- 关于生产者-消费者问题
- java生产者 消费者问题
- 消费者和生产者问题
- 生产者消费者问题
- 生产者消费者问题--多线程
- 生产者-消费者同步问题
- 生产者消费者问题
- 生产者与消费者问题
- 生产者 消费者问题!
- 生产者与消费者问题
- 生产者消费者问题
- 关于生产者-消费者问题
- 视觉slam闭环检测之-DBoW2 -视觉词袋构建
- 多人合作开发的体会
- 对象作用域代码分析
- jQuery技术——根据省份的选择动态加载相应城市
- App Store 上架流程
- 生产者消费者问题
- Windows 中以不同用户身份,复制文件到远程目录
- 静态变量、静态块与变量自增代码分析
- perl标量上下文小结
- String类常用方法练习
- Windows 删除共享文件夹
- Java 执行影音文件
- Intersection of Two Arrays问题及解法
- Map集合统计字母次数