zoukankan      html  css  js  c++  java
  • 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();
        }
    }

     

  • 相关阅读:
    结对开发:电梯调度(2)
    小组站立会议
    小组站立会议
    小组站立会议
    小组站立会议4月15日
    小组站立会议
    小组站立会议
    团队个人每天详细计划汇总
    Spring冲刺计划会议
    团队项目开发
  • 原文地址:https://www.cnblogs.com/Mrchengs/p/10798980.html
Copyright © 2011-2022 走看看