欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

生产者与消费者

时间:2023-04-22
生产者和消费者 目录

生产者和消费者

1.什么是生产者和消费者2.生产者和消费者(不加唤醒机制)3.生产者和消费者(加唤醒机制)4.解决虚假唤醒5.使用lock锁6.面试题 1.什么是生产者和消费者

​ 在日常生活中,我们去商店买东西,我们就是消费者,商店里面的某件商品有可能被卖完,那么这件商品就要生产(即进货),要保持两者统一。不能说顾客去买东西,商店里面没有就没有了,当商店里面没有东西之后就要去生产(进货),商店也是有限容量的,一件商品不能放太多,有个固定容量,生产的时候不能超过这个容量。

2.生产者和消费者(不加唤醒机制)

public class ProductorAndConsumer { public static void main(String[] args) { Market market = new Market(); Productor productor = new Productor(market); Consumer consumer = new Consumer(market); new Thread(productor,"生产者A").start(); new Thread(consumer,"消费者B").start(); }}//商店class Market{ //某件商品数量,最开始为0 private int product=0; //进货方法,在多线程环境下,如果不加锁会产生线程安全问题,这里加synchronized锁 public synchronized void get(){ //限定商店容量为10 if(product>=10){ System.out.println("仓库已满!"); }else{ System.out.println(Thread.currentThread().getName()+"进货成功!-->"+ ++product); } } //出售方法 public synchronized void sale(){ if(product<=0){ System.out.println("已售罄!"); }else { System.out.println(Thread.currentThread().getName()+"出售成功-->"+ --product); } }}//生产者,生产者不可能只有一个,所以是多线程的class Productor implements Runnable{ private Market market; public Productor(Market market){ this.market=market; } @Override public void run() { //一次买15个 for (int i=0;i<15;i++){ market.get(); } }}//消费者class Consumer implements Runnable{ private Market market; public Consumer(){} public Consumer(Market market){ this.market=market; } @Override public void run() { //一次买10个 for (int i=0;i<10;i++){ market.sale(); } }}

​ 当不加唤醒机制的生产者和消费者模式,出现售罄情况时不会立即去生产,出现仓库已满情况时也不会立即去出售,如下:

3.生产者和消费者(加唤醒机制)

public class ProductorAndConsumer { public static void main(String[] args) { Market market = new Market(); Productor productor = new Productor(market); Consumer consumer = new Consumer(market); new Thread(productor,"生产者A").start(); new Thread(consumer,"消费者B").start(); }}//商店class Market{ //某件商品数量,最开始为0 private int product=0; //进货方法,在多线程环境下,如果不加锁会产生线程安全问题,这里加synchronized锁 public synchronized void get(){ //限定商店容量为10 if(product>=10){ System.out.println("仓库已满!"); //当仓库已满,需要停止生产 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } }else{ System.out.println(Thread.currentThread().getName()+"进货成功!-->"+ ++product); //当进货成功,就需要唤醒 this.notifyAll(); } } //出售方法 public synchronized void sale(){ if(product<=0){ System.out.println("已售罄!"); //售罄之后需要停止去生产 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } }else { System.out.println(Thread.currentThread().getName()+"出售成功-->"+ --product); //出售成功之后需要生产 this.notifyAll(); } }}//生产者,生产者不可能只有一个,所以是多线程的class Productor implements Runnable{ private Market market; public Productor(Market market){ this.market=market; } @Override public void run() { //一次买15个 for (int i=0;i<15;i++){ market.get(); } }}//消费者class Consumer implements Runnable{ private Market market; public Consumer(){} public Consumer(Market market){ this.market=market; } @Override public void run() { //一次买10个 for (int i=0;i<10;i++){ market.sale(); } }}

​ 以上代码看起来没有什么问题,但是在实际运行时程序没有停止,如下图:

​ 分析问题原因,当生产者循环到最后一次时,消费者还有两次循环,当商品售罄之后,消费者会wait(),而生产者的循环已经结束,那么程序就一直会卡在wait(),不会结束。

4.解决虚假唤醒

​ 为了解决3出的问题,那么就要让消费者的最后一次循环中可以执行notifyAll()方法,这样才可以结束。

​ 那么就可以把else去掉,这样就可以使消费者最后一次执行结束,代码如下:

public class ProductorAndConsumer { public static void main(String[] args) { Market market = new Market(); Productor productor = new Productor(market); Consumer consumer = new Consumer(market); new Thread(productor,"生产者A").start(); new Thread(consumer,"消费者B").start(); new Thread(productor,"生产者C").start(); new Thread(consumer,"消费者D").start(); }}//商店class Market{ //某件商品数量,最开始为0 private int product=0; //进货方法,在多线程环境下,如果不加锁会产生线程安全问题,这里加synchronized锁 public synchronized void get(){ //限定商店容量为10 while(product>10){ System.out.println("仓库已满!"); //当仓库已满,需要停止生产 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+"进货成功!-->"+ ++product); //当进货成功,就需要唤醒 this.notifyAll(); } //出售方法 public synchronized void sale(){ while(product<=0){ System.out.println("已售罄!"); //售罄之后需要停止去生产 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+"出售成功-->"+ --product); //出售成功之后需要生产 this.notifyAll(); }}//生产者,生产者不可能只有一个,所以是多线程的class Productor implements Runnable{ private Market market; public Productor(Market market){ this.market=market; } @Override public void run() { //一次买15个 for (int i=0;i<15;i++){ market.get(); } }}//消费者class Consumer implements Runnable{ private Market market; public Consumer(){} public Consumer(Market market){ this.market=market; } @Override public void run() { //一次买10个 for (int i=0;i<10;i++){ market.sale(); } }}

​ 在修改以上代码中还出现了”虚假唤醒“的问题,即存在多个生产者和消费者的时候,当商店没有商品时,两个消费者都停在了wait()方法,然后生产者进行生产,生产一件之后,会执行notifyAll()方法,那么两个消费者都会去执行,就会出现商品不够的现象。

​ 为了解决以上问题,将if判断改成了while判断,生产者notifyAll()之后,消费者还需再次判断商品是否足够,不够继续wait()。

5.使用lock锁

​ 之前我们使用的是synchronized锁,我们现在改为lock同步锁进行替换。

【注意】:

使用lock锁的时候,必须要对其进行释放,一般放在finally中使用lock锁之后,需要使用Condition进行唤醒操作wait()方法变为await()方法notify()变为singnal()方法notifyAll()变为signalAll()方法

public class ProductorAndConsumer { public static void main(String[] args) { Market market = new Market(); Productor productor = new Productor(market); Consumer consumer = new Consumer(market); new Thread(productor,"生产者A").start(); new Thread(consumer,"消费者B").start(); new Thread(productor,"生产者C").start(); new Thread(consumer,"消费者D").start(); }}//商店class Market{ //某件商品数量,最开始为0 private int product=0; private Lock lock=new ReentrantLock(); private Condition condition=lock.newCondition(); //进货方法,在多线程环境下,如果不加锁会产生线程安全问题,这里加synchronized锁 public void get(){ lock.lock(); try{ //限定商店容量为10 while(product>10){ System.out.println("仓库已满!"); //当仓库已满,需要停止生产 try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+"进货成功!-->"+ ++product); //当进货成功,就需要唤醒 condition.signalAll(); }finally { lock.unlock(); } } //出售方法 public synchronized void sale(){ lock.lock(); try{ while(product<=0){ System.out.println("已售罄!"); //售罄之后需要停止去生产 try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+"出售成功-->"+ --product); //出售成功之后需要生产 condition.signalAll(); }finally { lock.unlock(); } }}//生产者,生产者不可能只有一个,所以是多线程的class Productor implements Runnable{ private Market market; public Productor(Market market){ this.market=market; } @Override public void run() { //一次买15个 for (int i=0;i<15;i++){ market.get(); } }}//消费者class Consumer implements Runnable{ private Market market; public Consumer(){} public Consumer(Market market){ this.market=market; } @Override public void run() { //一次买10个 for (int i=0;i<10;i++){ market.sale(); } }}

6.面试题

​ 使用多线程实现先打印线程AA打印”AA“5次,线程BB打印”BB“10次,线程CC打印”CC“15次,总共打印10轮。

​ 【使用Lock中的Condition】

public class test { private static Integer a = 1; public static void main(String[] args) { add add = new add(); new Thread(()->{ for (int i=0;i<10;i++){ add.printAA(i); } },"AA").start();new Thread(()->{ for (int i=0;i<10;i++){ add.printBB(i); } },"BB").start();new Thread(()->{ for (int i=0;i<10;i++){ add.printCC(i); } },"CC").start(); }}class add{ private int flag=1; private Lock lock=new ReentrantLock(); Condition condition1=lock.newCondition(); Condition condition2=lock.newCondition(); Condition condition3=lock.newCondition(); //打印AA void printAA(int loop){ lock.lock(); try{ while (flag!=1){ try { condition1.await(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i < 5; i++) { System.out.println("AA"+"轮数:"+(loop+1)); } flag++; condition2.signal(); }finally { lock.unlock(); } } //打印BB void printBB(int loop){ lock.lock(); try{ while (flag!=2){ try { condition2.await(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i < 10; i++) { System.out.println("BB"+"轮数:"+(loop+1)); } flag++; condition3.signal(); }finally { lock.unlock(); } } //打印CC void printCC(int loop){ lock.lock(); try{ while (flag!=3){ try { condition3.await(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i < 15; i++) { System.out.println("CC"+"轮数:"+(loop+1)); } flag=1; condition1.signal(); }finally { lock.unlock(); } }}

【使用Object中的wait、notify、notifyAll】

public class test { private static Integer a = 1; public static void main(String[] args) { add add = new add(); new Thread(()->{ for (int i=0;i<10;i++){ add.printAA(i); } },"AA").start();new Thread(()->{ for (int i=0;i<10;i++){ add.printBB(i); } },"BB").start();new Thread(()->{ for (int i=0;i<10;i++){ add.printCC(i); } },"CC").start(); }}class add{ private int flag=1; //打印AA synchronized void printAA(int loop){ while (flag!=1){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } flag++; for (int i = 0; i < 5; i++) { System.out.println("AA"+"轮数:"+(loop+1)); } this.notifyAll(); } //打印BB synchronized void printBB(int loop){ while (flag!=2){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } flag++; System.out.println("BB"+"轮数:"+(loop+1)); this.notifyAll(); } //打印CC synchronized void printCC(int loop){ while (flag!=3){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } flag=1; System.out.println("CC"+"轮数:"+(loop+1)); this.notifyAll(); }}

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。