多线程(11)线程通信
一:应用场景:生产者和消费者问题
①假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中产品取走消费
②如果仓库中没有产品,则生产者将产品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者取走为止
③如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费并等待,直到仓库中再次放入产品为止。
二:分析
这是一个线程通信同步问题,生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件
①对于生产者,没有生产产品之前,要通知消费者等待,而生产了产品之后,又需要马上通知消费者消费
②对于消费者,在消费之后,要通知生产者已经结束消费,需要生产新的产品以供消费
③在生产者消费者问题中,仅有synchronized是不够的
synchronized可阻止并发更新同一个共享资源,实现同步
synchronized不能用来实现不同线程之间的消息传递(通信)
三:java提供了几个方法解决线程之间的通信问题
①wait():表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁
②wait(long timeout);指定等待的毫秒数
③notify():唤醒一个处于等待状态的线程
④notifyAll();唤醒同一个对象上所有调用wait()方法的线程,优先级高的线程优先调度。
四:解决方式一(管程法)
①生产者:负责生产数据的模块
②消费者:负责处理数据的模块
③缓冲区:消费者不能直接使用生产者的数据,他们之间有个缓冲区
生产者将生产好的数据放入缓冲区,消费者从缓冲区拿出数据
//测试:生产者消费者模型--》利用缓存区解决;管程法 //生产者,消费者,产品,缓存区 public class TestPro { public static void main(String[] args) { SynContainer synContainer=new SynContainer(); new Product(synContainer).start(); new Consumer(synContainer).start(); } } //生产者 class Product extends Thread { SynContainer container; public Product(SynContainer container) { this.container = container; } //生产 @Override public void run() { for (int i = 0; i < 100; i++) { container.push(new Chickde(i)); System.out.println("生产了" + i + "只鸡"); } } } //消费者 class Consumer extends Thread{ SynContainer container; public Consumer(SynContainer container){ this.container=container; } //消费 @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("消费了----"+container.pop().id+"只鸡"); } } } //产品 class Chickde{ int id; Chickde(int id){ this.id=id; } } //缓存区 class SynContainer{ //需要一个容器大小 Chickde[] chickdes=new Chickde[10]; //容器计数器 int count=0; //生产者放入产品 public synchronized void push(Chickde chickde){ //如果容器满了,就需要等待消费者 if (count==chickdes.length){ //通知消费者消费,生产等待 try { this.wait(); }catch (InterruptedException e){ e.printStackTrace(); } } //如果没有满,我们就需要丢入产品 chickdes[count]=chickde; count++; //可以通知消费者消费了 this.notifyAll(); } //消费者消费产品 public synchronized Chickde pop(){ //判断能否消费 if (count==0){ //等待生产者生产,消费者等待 try{ this.wait(); }catch (InterruptedException e){ e.printStackTrace(); } } //如果可以消费 count--; Chickde chickde=chickdes[count]; //吃完了,通知生产者生产 this.notifyAll(); return chickde; } } 生产了0只鸡 生产了1只鸡 生产了2只鸡 生产了3只鸡 生产了4只鸡 生产了5只鸡 生产了6只鸡 生产了7只鸡 生产了8只鸡 生产了9只鸡 消费了----9只鸡 消费了----8只鸡 消费了----7只鸡 消费了----6只鸡 消费了----5只鸡 消费了----4只鸡 消费了----3只鸡 消费了----2只鸡 消费了----1只鸡 消费了----0只鸡 生产了10只鸡 生产了11只鸡 生产了12只鸡 生产了13只鸡 生产了14只鸡 生产了15只鸡 生产了16只鸡 生产了17只鸡 生产了18只鸡 生产了19只鸡 生产了20只鸡 消费了----10只鸡 消费了----20只鸡 消费了----19只鸡 消费了----18只鸡 消费了----17只鸡 消费了----16只鸡 消费了----15只鸡 消费了----14只鸡 消费了----13只鸡 消费了----12只鸡 消费了----11只鸡 生产了21只鸡 生产了22只鸡 生产了23只鸡 生产了24只鸡 生产了25只鸡 生产了26只鸡 生产了27只鸡 生产了28只鸡 生产了29只鸡 生产了30只鸡 生产了31只鸡 消费了----26只鸡 消费了----31只鸡 消费了----30只鸡 消费了----29只鸡 消费了----32只鸡 消费了----28只鸡 消费了----27只鸡 消费了----25只鸡 消费了----24只鸡 消费了----23只鸡 消费了----22只鸡 消费了----21只鸡 生产了32只鸡 生产了33只鸡 生产了34只鸡 生产了35只鸡 生产了36只鸡 生产了37只鸡 生产了38只鸡 生产了39只鸡 生产了40只鸡 生产了41只鸡 生产了42只鸡 消费了----42只鸡 消费了----41只鸡 消费了----40只鸡 消费了----39只鸡 消费了----38只鸡 消费了----37只鸡 消费了----36只鸡 消费了----35只鸡 消费了----34只鸡 消费了----33只鸡 生产了43只鸡 生产了44只鸡 生产了45只鸡 生产了46只鸡 生产了47只鸡 生产了48只鸡 生产了49只鸡 生产了50只鸡 生产了51只鸡 生产了52只鸡 消费了----52只鸡 消费了----51只鸡 消费了----50只鸡 消费了----49只鸡 消费了----48只鸡 消费了----47只鸡 消费了----46只鸡 消费了----45只鸡 消费了----44只鸡 消费了----43只鸡 生产了53只鸡 生产了54只鸡 生产了55只鸡 生产了56只鸡 生产了57只鸡 生产了58只鸡 生产了59只鸡 生产了60只鸡 生产了61只鸡 生产了62只鸡 消费了----62只鸡 消费了----61只鸡 消费了----60只鸡 消费了----59只鸡 消费了----58只鸡 生产了63只鸡 生产了64只鸡 生产了65只鸡 生产了66只鸡 消费了----63只鸡 消费了----67只鸡 消费了----66只鸡 消费了----65只鸡 消费了----64只鸡 消费了----57只鸡 消费了----56只鸡 消费了----55只鸡 消费了----54只鸡 消费了----53只鸡 生产了67只鸡 生产了68只鸡 生产了69只鸡 生产了70只鸡 生产了71只鸡 生产了72只鸡 生产了73只鸡 生产了74只鸡 生产了75只鸡 生产了76只鸡 生产了77只鸡 消费了----77只鸡 消费了----76只鸡 消费了----75只鸡 消费了----74只鸡 消费了----78只鸡 消费了----73只鸡 消费了----72只鸡 消费了----71只鸡 消费了----70只鸡 消费了----69只鸡 消费了----68只鸡 生产了78只鸡 生产了79只鸡 消费了----79只鸡 消费了----80只鸡 生产了80只鸡 生产了81只鸡 生产了82只鸡 生产了83只鸡 生产了84只鸡 生产了85只鸡 生产了86只鸡 生产了87只鸡 生产了88只鸡 生产了89只鸡 生产了90只鸡 消费了----90只鸡 生产了91只鸡 生产了92只鸡 消费了----91只鸡 消费了----92只鸡 生产了93只鸡 生产了94只鸡 消费了----93只鸡 消费了----94只鸡 生产了95只鸡 生产了96只鸡 消费了----95只鸡 消费了----96只鸡 生产了97只鸡 生产了98只鸡 消费了----97只鸡 消费了----98只鸡 生产了99只鸡 消费了----99只鸡 消费了----89只鸡 消费了----88只鸡 消费了----87只鸡 消费了----86只鸡 消费了----85只鸡 消费了----84只鸡 消费了----83只鸡 消费了----82只鸡 消费了----81只鸡
解决方式二(信号灯法)
①通过一个标志位来判断
//测试生产者消费者问题2:信号灯法,标志位解决 public class TestPc2 { public static void main(String[] args) { TV tv=new TV(); new Player(tv).start(); new Watchrer(tv).start(); } } //生产者---》演员 class Player extends Thread{ TV tv; public Player(TV tv){ this.tv=tv; } @Override public void run() { for (int i=0;i<20;i++){ if (i%2==0){ this.tv.play("快乐大本营播放中"); }else { this.tv.play("抖音:记录美好生活"); } } } } //消费者--->观众 class Watchrer extends Thread{ TV tv; public Watchrer(TV tv){ this.tv=tv; } @Override public void run() { for (int i=0;i<20;i++){ tv.watch(); } } } //观众---》节目 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; } } 演员表演了:快乐大本营播放中 观看了:快乐大本营播放中 演员表演了:抖音:记录美好生活 观看了:抖音:记录美好生活 演员表演了:快乐大本营播放中 观看了:快乐大本营播放中 演员表演了:抖音:记录美好生活 观看了:抖音:记录美好生活 演员表演了:快乐大本营播放中 观看了:快乐大本营播放中 演员表演了:抖音:记录美好生活 观看了:抖音:记录美好生活 演员表演了:快乐大本营播放中 观看了:快乐大本营播放中