zoukankan      html  css  js  c++  java
  • synchronized&Object类的wait/notify/notifyAll(生产者消费者场景)

    Java中的每一个对象都有一个监视器

    Object类的wait和notify、notifyAll方法必须在synchronized块中调用

    调用一个对象的notify、notifyAll方法时,当前线程必须持有该对象的监视器monitor,否则抛出IllegalMonitorStateException

    如果在synchronized块中调用另一个对象的notify、notifyAll方法,由于持有的对象的监视器不同,抛出IllegalMonitorStateException


    (1)synchronized块

           synchronized(lock){

      }

      synchronized块中的方法,获得了lock实例的monitor

    
    

    (2)实例synchronized方法

      public synchronized void run() {

      }

      获得了this对象的monitor

    (3)静态synchronized方法

      public static synchronized void run() {

      }

      获得了当前类的所有对象的monitor


    (1)wait()

    一个持有当前对象的monitor的线程调用了当前对象的空参的wait方法,使得当前线程进入WARTING状态,释放锁

    必须等待另一个持有当前对象的monitor的线程调用当前对象的notify或者notifyAll方法将该线程唤醒

     

    (2)wait(long)

     norify

    notifyAll

    等待时间到

    interrupt

    (3)wait(long,int)

      

      wait方法必须总是存在于循环中

      

    生产者、消费者场景

    /**
     * @author DuanJiaPing
     * @date 2018/6/11 9:08
     *
     * 等待喚醒機制
     *
     *
     * Object類的方法
     * wait()
     * notify()
     * notifyAll()
     *
     * 生產者和消費者案例
     * 生產者生產的產品給店員,消費者從店員那獲取產品
     *
     * 生产者线程:创建和添加数据的线程
     * 消费者线程:删除和销毁数据的线程
     *
     * 生产者消费者案例不使用等待唤醒机制
     * 会产生以下问题
     * 数据丢失:生产者线程过快,另一面接受不到
     * 数据重复:消费者线程过快
     *
     *
     * 问题:程序结束不了
     * wait():等在方法调用处,并释放锁,当被notify或notifyAll方法唤醒之后,在等待的位置处继续执行
     * 线程被唤醒之后,被唤醒的线程和唤醒线程的线程同时抢锁
     * 解决:把notifyAll方法移到else之外
     *
     * 虚假唤醒问题:
     * 当前库存超过了最大库存或者小于0的情况
     * 解决:
     * Java API
     * wait()方法提示:应当将wait方法总是放在循环中
     *
     */
    public class TestProductorAndConsumer {
    
    
        public static void main(String[] args){
            Clerk clerk = new Clerk();
            Productor productor = new Productor(clerk);
            Consumer consumer = new Consumer(clerk);
    
            new Thread(productor,"生产者A").start();
            new Thread(productor,"生产者B").start();
            new Thread(consumer,"消费者1").start();
            new Thread(consumer,"消费者2").start();
    
        }
    
    
    }
    
    /*
    * 店员类
    * 店员进货、售货,只有一个店员
    * */
    
    class Clerk{
    
        /*库存*/
    
        private int product = 0;
    
        /*
        * 此时,进货和售货的两个方法都操作共享数据product(库存)
        * 因此,这两个方法都存在线程安全问题
        * 解决:同步方法,同步代码块
        *
        * */
    
        /*
        * 进货
        * */
    
        public synchronized void get(){
    
            while (product >= 5) {
                System.out.println("库存已满");
                try{
                    //将wait放在while循环中,当多个线程在此处等待,并被notifyAll唤醒之后,会再循环判断一次product的值
                    wait();
                }catch(Exception e){
    
                }
            }
    //        if(product >= 1) {
    //            System.out.println("库存已满");
    //            try{
    //                wait();//当两个线程同时wait在此处,notifyAll之后,两个线程都从这块开始执行,都执行下面的sysout,都将product(库存)加一
    //            }catch(Exception e){
    //
    //            }
    //        }
    
            /*else{
                System.out.println(Thread.currentThread().getName()+"--进货--当前库存--"+ ++product);
    
                notifyAll();
            }*/
    
            System.out.println(Thread.currentThread().getName()+"--进货--当前库存--"+ ++product);
    
            notifyAll();
    
        }
    
        /*
        * 售货
        * */
    
        public synchronized void sale(){
            while(product <= 0){
                System.out.println("库存不足");
                try{
                    wait();
                }catch(Exception e){
    
                }
            }
    
            System.out.println(Thread.currentThread().getName()+"--售货--当前库存--"+ --product);
    
            notifyAll();
        }
    }
    
    
    /*生产者类,生产者生产产品提供给店员
    * 生产者有多个
    * 多线程
    * */
    
    class Productor implements Runnable{
        private Clerk clerk;
    
        public Productor(Clerk clerk) {
            this.clerk = clerk;
        }
    
        @Override
        public void run() {
            //不断生产10个产品,提供给店员
            try{
                Thread.sleep(200);
            }catch (Exception e){
    
            }
    
            for(int i=1;i<=10;i++){
                clerk.get();
            }
        }
    }
    
    
    /*消费者类
    * 消费者从店员处购买产品
    * 多个消费者
    * 多线程*/
    
    class Consumer implements Runnable{
        private Clerk clerk;
    
        public Consumer(Clerk clerk) {
            this.clerk = clerk;
        }
    
        @Override
        public void run() {
            for(int i=1;i<=10;i++){
                clerk.sale();
            }
    
        }
    }



  • 相关阅读:
    解决Maven下载速度缓慢问题
    IntelliJ IDEA 最新激活码
    Googel 浏览器 模拟发送请求工具--Advanced REST Client
    Firefox火狐 浏览器接口调试工具 JSON 格式化
    修复/lib/ld-linux.so.2: bad ELF interpreter: No such file or directory问题
    解决Nginx: [error] open() "/usr/local/Nginx/logs/Nginx.pid
    configure: error: You need a C++ compiler for C++ support.[系统缺少c++环境]
    解决编译apache出现的问题:configure: error: APR not found . Please read the documentation
    centos6 Linux安装redis 2.6.14
    Nginx+Tomcat负载均衡配置
  • 原文地址:https://www.cnblogs.com/duanjiapingjy/p/9432825.html
Copyright © 2011-2022 走看看