在生产者跟消费模式中常用两种方法来处理并发问题,管程法跟信用灯法
- 管程法:常用一个缓冲区来处理通知唤醒跟等待
- 信号灯法:常用一个标识位来处理唤醒跟等待操作
管程法:
1 package 多线程练习.锁学习.生产者消费模式; 2 3 public class 管程法 { 4 public static void main(String[] args) { 5 Syncontainer syncontainer = new Syncontainer(); 6 Producer producer = new Producer(syncontainer); 7 Consumer consumer = new Consumer(syncontainer); 8 new Thread(producer, "生产者").start(); 9 new Thread(consumer, "消费者").start(); 10 } 11 } 12 13 14 class Chicken { 15 int id; 16 17 public Chicken(int id) { 18 this.id = id; 19 } 20 } 21 22 class Producer implements Runnable { 23 24 Syncontainer syncontainer; 25 26 public Producer(Syncontainer syncontainer) { 27 this.syncontainer = syncontainer; 28 } 29 30 @Override 31 public void run() { 32 for (int i = 0; i < 100; i++) { 33 System.out.println("生产了" + i + "只鸡"); 34 syncontainer.push(new Chicken(i)); 35 } 36 } 37 } 38 39 class Consumer implements Runnable { 40 41 Syncontainer syncontainer; 42 43 public Consumer(Syncontainer syncontainer) { 44 this.syncontainer = syncontainer; 45 } 46 47 @Override 48 public void run() { 49 for (int i = 0; i < 100; i++) { 50 System.out.println("消费了" + syncontainer.pop().id + "只鸡"); 51 } 52 } 53 } 54 55 class Syncontainer { 56 // 缓冲区最多可以存放10只鸡 57 Chicken[] chickens = new Chicken[10]; 58 // 计数器 59 int count = 0; 60 61 // 生产者放入产品 62 public synchronized void push(Chicken chicken) { 63 // 判断容器内有没有产品 没有就通知生产者生产 消费者等待 64 if (count == chickens.length) { 65 // 里面的容量已经满了 去通知消费者消费 66 try { 67 this.wait(); 68 } catch (InterruptedException e) { 69 e.printStackTrace(); 70 } 71 } 72 73 chickens[count] = chicken; 74 count++; 75 76 77 // 通知消费者消费 78 this.notifyAll(); 79 80 } 81 82 // 消费者消费产品 83 public synchronized Chicken pop() { 84 if (count == 0) { 85 // 容器中空了 通知生产者生产 消费者等待 86 try { 87 this.wait(); 88 } catch (InterruptedException e) { 89 e.printStackTrace(); 90 } 91 } 92 93 94 count--; 95 Chicken chicken = chickens[count]; 96 97 // 通知生产者生产 98 this.notifyAll(); 99 100 101 return chicken; 102 } 103 }
管程法输出结果:
信号灯法:
package 多线程练习.锁学习.生产者消费模式; import org.omg.CORBA.TCKind; public class 信号灯法 { public static void main(String[] args) { Tv tv = new Tv(); Productor02 p = new Productor02(tv); Consumer02 c = new Consumer02(tv); new Thread(p).start(); new Thread(c).start(); } } class Productor02 implements Runnable { Tv tv; public Productor02(Tv tv) { this.tv = tv; } @Override public void run() { for (int i = 0; i < 20; i++) { if (i % 2 == 0) { tv.player("还珠格格"); } else { tv.player("广告时间"); } } } } class Consumer02 implements Runnable { Tv tv; public Consumer02(Tv tv) { this.tv = tv; } @Override public void run() { for (int i = 0; i < 20; i++) { tv.SeeTv(); } } } class Tv { Boolean flag = true; // 这就是个信号灯 // 当flag true 电视播放 观众停止 false:电视停止 观众观看 String tvName; // 观众观看 public synchronized void SeeTv() { if (flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("观众正在观看电视节目" + this.tvName); this.notifyAll(); // 通知player继续播放下个节目 flag = !flag; } //电视播放 public synchronized void player(String tvName) { // 观众在观看的试试 不能换台 if (!flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("电视机正在播放" + tvName); this.tvName = tvName; //将本地额tvname更新 防止观众看了个寂寞 this.notifyAll(); // 通知player继续播放下个节目 flag = !flag; } }
信号灯法输出结果: