1、生产者、消费者
2、管程法
(1)创建生产者:
public class Productor extends Thread{ SynContainer synContainer; public Productor(SynContainer synContainer){ this.synContainer=synContainer; } public void run(){ for(int i=0;i<10;i++){ synContainer.push(new Chicken(i)); System.out.println("生产了"+i+"只鸡"); } } }
(2)创建消费者:
public class Consume extends Thread { SynContainer synContainer; public Consume(SynContainer synContainer){ this.synContainer=synContainer; } public void run(){ for(int i=0;i<10;i++){ System.out.println("消费了第"+i+"只鸡"); } } }
(3)创建产品类:
public class Chicken { int id; public Chicken(int id) { this.id=id; } }
(4)创建同步代码:
public class SynContainer { Chicken[] chickens=new Chicken[10]; //容器计数器 int count=0; //生产者生产产品 public synchronized void push(Chicken chicken){ //如果容器满了,就需要等待消费的消费 if(count==chickens.length){ //通知消费者消费 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //如果没有满就需要丢入产品 chickens[count]=chicken; count++; this.notifyAll(); } public synchronized Chicken pop(){ //判断能否消费 if(count==0){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //如果可以消费,就消费 count--; Chicken chicken=chickens[count]; //吃完了,通知生产者生产 this.notifyAll(); return chicken; } }
保证容器中没有产品的时候生产产品,不能消费;容器中产品满了的时候,不能再去生产产品
(5)创建测试类:
public class Test { public static void main(String[] args) { SynContainer synContainer=new SynContainer(); new Productor(synContainer).start(); new Consume(synContainer).start(); } }
(6)测试:
生产了0只鸡
生产了1只鸡
生产了2只鸡
生产了3只鸡
生产了4只鸡
生产了5只鸡
生产了6只鸡
生产了7只鸡
生产了8只鸡
生产了9只鸡
消费了第0只鸡
消费了第1只鸡
消费了第2只鸡
消费了第3只鸡
消费了第4只鸡
消费了第5只鸡
消费了第6只鸡
消费了第7只鸡
消费了第8只鸡
消费了第9只鸡
3、信号灯法
(1)创建生产者:
//生产者:演员 public class Player extends Thread { TV tv; public Player(TV tv){ this.tv=tv; } public void run(){ for (int i = 0; i < 20; i++) { if(i%2==0){ this.tv.play("猫和老鼠"); }else { this.tv.play("海绵宝宝"); } } } }
(2)创建消费者:
//消费者:观众 public class Watcher extends Thread { TV tv; public Watcher(TV tv){ this.tv=tv; } public void run(){ for (int i = 0; i < 20; i++) { tv.watch(); } } }
(3)书写同步代码:
//产品:节目 public class TV { //演员表演,观众等待 //观众观看,演员等待 String voice;//表演的节目 boolean flag=true; //表演 public synchronized void play(String voice){ if(!flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("演员表演了:"+voice); //通知观众观看 this.notifyAll();//唤醒 this.voice=voice; this.flag=!this.flag; } //观看 public synchronized void watch(){ if(flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("观看了"+voice); //通知演员表演 this.notifyAll(); this.flag=!this.flag; } }
(4)创建测试类:
//通过标志位解决 public class Test { public static void main(String[] args) { TV tv=new TV(); new Player(tv).start(); new Watcher(tv).start(); } }
(5)测试:
演员表演了:猫和老鼠
观看了猫和老鼠
演员表演了:海绵宝宝
观看了海绵宝宝
演员表演了:猫和老鼠
观看了猫和老鼠
演员表演了:海绵宝宝
观看了海绵宝宝
演员表演了:猫和老鼠
观看了猫和老鼠
演员表演了:海绵宝宝
观看了海绵宝宝
演员表演了:猫和老鼠
观看了猫和老鼠
演员表演了:海绵宝宝
观看了海绵宝宝
演员表演了:猫和老鼠
观看了猫和老鼠
演员表演了:海绵宝宝
观看了海绵宝宝
演员表演了:猫和老鼠
观看了猫和老鼠
演员表演了:海绵宝宝
观看了海绵宝宝
演员表演了:猫和老鼠
观看了猫和老鼠
演员表演了:海绵宝宝
观看了海绵宝宝
演员表演了:猫和老鼠
观看了猫和老鼠
演员表演了:海绵宝宝
观看了海绵宝宝
演员表演了:猫和老鼠
观看了猫和老鼠
演员表演了:海绵宝宝
观看了海绵宝宝
演员表演了:猫和老鼠
观看了猫和老鼠
演员表演了:海绵宝宝
观看了海绵宝宝
(6)与管程法的最大不同就是,用信号灯法需要设置一个标志位,而管程法是设置一个变量,根据变量的值来进行