7、JUC--JUC线程高级_生产者消费者案例-虚假唤醒
等待唤醒案例最经典的的就是:生产者消费者案例
首先定义一个店员进行买卖产品:
//店员 class Clerk{ private int product =0; //进货 public synchronized void get(){ 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); } } }
此时是对共享数据进行操作使用synchronized进行操作!!
生产者进行生产产品:
class Product implements Runnable{ private Clerk clerk; public Product(Clerk clerk){ this.clerk = clerk; } @Override public void run() { //进行生产产品 for(int i=0;i<20;i++){ clerk.get(); } } }
消费者进行购买产品:
class Consumer implements Runnable{ private Clerk clerk; public Consumer(Clerk clerk){ this.clerk = clerk; } @Override public void run() { //消费者进行消费产品 //进行生产产品 for(int i=0;i<20;i++){ clerk.sale(); } } }
public static void main(String[] args) { Clerk clerk = new Clerk(); Product product=new Product(clerk); Consumer consumer = new Consumer(clerk); new Thread(product,"生产者").start(); new Thread(consumer,"消费者").start(); }
执行结果如下
此时可以发现是线程不安全的
生产者消费者过快都会影响数据
进行数据的等待和唤醒
class Clerk{ private int product =0; //进货 public synchronized void get(){ 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 Clerk{ private int product =0; //进货 public synchronized void get(){ if(product >=1){ System.out.println("产品已满!"); try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block 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) { // TODO Auto-generated catch block e.printStackTrace(); } }else{ System.out.println(Thread.currentThread().getName()+":"+ --product); this.notifyAll(); } } } //生产者 class Product implements Runnable{ private Clerk clerk; public Product(Clerk clerk){ this.clerk = clerk; } @Override public void run() { //进行生产产品 for(int i=0;i<20;i++){ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } clerk.get(); } } } //消费者 class Consumer implements Runnable{ private Clerk clerk; public Consumer(Clerk clerk){ this.clerk = clerk; } @Override public void run() { //消费者进行消费产品 //进行生产产品 for(int i=0;i<20;i++){ clerk.sale(); } } }
此时的运行结果:
运行结束之后,线程并未关闭
此时出现问题的位置:
此时的程序执行位置再wait()处,没有代码进行唤醒
程序会处于等待唤醒的状态
解决方法去点else
class Clerk{ private int product =0; //进货 public synchronized void get(){ if(product >=1){ System.out.println("产品已满!"); try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } 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) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+":"+ --product); this.notifyAll(); } }
增加生产者消费者
public static void main(String[] args) { Clerk clerk = new Clerk(); Product product=new Product(clerk); Consumer consumer = new Consumer(clerk); new Thread(product,"生产者").start(); new Thread(consumer,"消费者").start(); new Thread(product,"生产者1").start(); new Thread(consumer,"消费者1").start(); }
查看Java API中的wait()方法
为了避免虚假唤醒问题,应当总是在循环中使用
代码进行升级
class Clerk{ private int product =0; //进货 public synchronized void get(){ while(product >=1){ System.out.println("产品已满!"); try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block 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) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+":"+ --product); this.notifyAll(); } }