直接看代码:
package beijing.lele; public class ProduceConsumeThread { /** * 对于线程死锁,用生产消费者模式|方案来解决, 生活中,人车 共用车道资源也是生产者消费者现象 * 生产者消费者模式有两种解决方式: * 1 用容器,容器满了 就停止 2 信号灯法,标识位 (这种方式下,必须要 this.wait() + this.notify() + synchronized 才生效) */ /** 这是没修改前跑出来的结果: 电影院1 生产了: 天空电影 李四消费了: 天空电影 电影院1 生产了: 草地电影 张三消费了: 草地电影 李四消费了: 草地电影 张三消费了: 草地电影 电影院1 生产了: 天空电影 张三消费了: 天空电影 修改成功后的结果: 电影院1 生产了: 天空电影 李四消费了: 天空电影 电影院1 生产了: 草地电影 张三消费了: 草地电影 电影院1 生产了: 天空电影 张三消费了: 天空电影 * @param args */ public static void main(String[] args) { Moive moive = new Moive(); // 多线程必须是对同一个对象moive的引用才能会在 moive方法中的 this.wait() this.notify()生效 OK了 //MyMoive1 moive = new MyMoive1(); 原版OK的 //Moive0 moive = new Moive0(); OK了 new Thread(new Producer(moive),"电影院1").start();// 类Producer和Consumer共同持有moive这个公共对象类,但是分别调用这个moive类的生产和消费方法。 new Thread(new Consumer(moive),"张三").start();// 而在公共持有类moive的生产和消费这两个方法中,使用信号灯来控制对方的等待和执行 new Thread(new Consumer(moive),"李四").start(); } } //业务类 class MyMoive1 { String msg; private boolean flag = false; // 生产 synchronized void play(String msg) { while (flag) { try { wait(); } catch (InterruptedException e) { System.out.println("InterruptedException caught"); } } try { Thread.sleep(250) ;// 生产耗时 } catch (InterruptedException e) { e.printStackTrace(); } this.msg = msg; System.out.println(Thread.currentThread().getName() + "--生产电影: " + msg); flag = true; notifyAll(); } // 消费 synchronized void watch() { while (!flag) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } try { Thread.sleep(250) ;// 消费耗时 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "--消费: " + msg); flag = false; notifyAll(); } } //业务类 class Moive0{ private String msg ; // flag=true时, 生产者生产,消费者等待,生产完毕后通知消费者 // flag=false时,生产者等待,消费者消费,消费完毕后通知生产者 private boolean flag = true; // 生产 public synchronized void play(String msg) { while(!flag) {// flag= false时 等待消费 try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 开始生产 flag = true时开始生产 try { Thread.sleep(300);// 模拟生产数据的耗时 } catch (InterruptedException e) { e.printStackTrace(); } this.msg = msg; System.out.println(Thread.currentThread().getName() +" 生产了: " + msg); // 通知消费 flag = false; notifyAll(); } // 消费 public synchronized void watch() { while(flag) {// flag=true时,开始生产,此时消费方法进行等待 try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 开始消费 try { Thread.sleep(300);// 模拟消费数据的耗时 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() +"消费了: " + msg); // 通知消费 flag = true; notifyAll(); } } //业务类 class Moive{ private String msg ; // flag=true时, 生产者生产,消费者等待,生产完毕后通知消费者 // flag=false时,生产者等待,消费者消费,消费完毕后通知生产者 private boolean flag = true; // 生产 public synchronized void play(String msg) { while(!flag) {// 等待消费 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 开始生产 try { Thread.sleep(300);// 模拟生产数据的耗时 } catch (InterruptedException e) { e.printStackTrace(); } this.msg = msg; System.out.println(Thread.currentThread().getName() +" 生产了: " + msg); // 通知消费 this.flag = false; this.notifyAll(); } // 消费 public synchronized void watch() { while(flag) {// 等待生产 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 开始消费 try { Thread.sleep(300);// 模拟消费数据的耗时 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() +"消费了: " + msg); // 通知消费 this.flag = true; this.notifyAll(); } } // 生产者 class Producer implements Runnable{ //private MyMoive1 moive; private Moive moive; //private Moive0 moive; public Producer() { } //public Producer(MyMoive1 moive) { public Producer(Moive moive) { //public Producer(Moive0 moive) { this.moive = moive; } @Override public void run() { for(int i=0; i<50; i++) { if(i%2 == 0) { moive.play("天空电影"); }else{ moive.play("草地电影"); } } } } // 消费者 class Consumer implements Runnable{ //private MyMoive1 moive; // 公共持有类, 此类上持有业务方法 private Moive moive; //private Moive0 moive; public Consumer() { } //public Consumer(MyMoive1 moive) { public Consumer(Moive moive) { //public Consumer(Moive0 moive) { this.moive = moive; } @Override public void run() { for(int i=0; i<50; i++) { moive.watch(); } } }
和单生产者单消费者代码的区别在:
Movie业务类的 生产和消费方法中:
前者是用:
if(!flag) { 后者用 while(!flag) {