• java多线程(7)---Condition


    Condition

    一、Condition概述

           在线程的同步时可以使一个线程阻塞而等待一个信号,同时放弃锁使其他线程可以能竞争到锁。

           在synchronized中我们可以使用Object的wait()和notify方法实现这种等待和唤醒。

           在Lock可以实现相同的功能就是通过Condition。Condition中的await()和signal()/signalAll()就相当于Object的wait()和notify()/notifyAll()。

    除此之外,Condition还是对多线程条件进行更精确的控制。notify()是唤醒一个线程,但它无法确认是唤醒哪一个线程。 但是,通过Condition,就能明确的指定唤醒读线程。

    二、Condition和Object案例对比

           案例说明:生成者在仓库满时,进入等待状态,同时唤醒消费者线程,消费者在仓库为空时,进入等待。同时唤醒生产者线程。

    1、采用await()和signal()方式

    (1)测试类

    public class ConditionLockTest {
    
        public static void main(String[] args){
    
            //相当于仓库
            Depot depot=new Depot();
            
          //创建两个生产者一个消费者
            Producer producer1=new Producer(depot);
            Producer producer2=new Producer(depot);
            Consumer consumer1=new Consumer(depot);
            
          //采用线程池方式
            Executor executors=Executors.newFixedThreadPool(5);
            executors.execute(producer1);
            executors.execute(producer2);
            executors.execute(consumer1);
        }
    }
    
    //生产者
    class Producer implements  Runnable {
    
        Depot depot;
        public Producer(Depot depot){
            this.depot=depot;
        }
        public void  run(){
         while(true){
            depot.prod();
           }
        }
    }
    
    //消费者
    class Consumer implements  Runnable{
        
        Depot depot;  
        public Consumer(Depot depot){
            this.depot=depot;
        }
        public void run(){
         while(true){
            depot.consum();
          }
       }
    }

    (2)仓库类

    public class Depot {
       //初始仓库为0,最大为10,超过10生产者停止生产
        private int size;
        private int maxSize=10;
    
        private Condition prodCondition;
        private Condition consumCondition;
    
        private Lock lock;
        public Depot(){
    
            this.size=0;
            this.lock=new ReentrantLock();
            //可以看出Condition对象依赖于Lock锁
            this.prodCondition=this.lock.newCondition();
            this.consumCondition=this.lock.newCondition();
        }
    
        /*
         * 生产者生产方法
         */
        public void prod(){
    
            lock.lock();
            try{
              //如果生产超过max值,则生产者进入等待
                while(size+1>maxSize){
                    try {
                        System.out.println(Thread.currentThread().getName()+"生产者进入等待状态");
                        prodCondition.await();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                size+=1;        
                System.out.println(Thread.currentThread().getName()+" 生产了一个 "+1+" 总共还有 "+size);
                
                //唤醒消费者线程
                consumCondition.signal(); 
    
            }finally {
                lock.unlock();
            }
        }
    
        /*
         * 消费者消费方法
         */
        public void consum(){
    
            lock.lock();
            try{
                //如果当前大小减去要消费的值,如果小于0的话,则进入等待
                while(size-1<0){
                    try {
                         System.out.println(Thread.currentThread().getName()+" 消费者进入等待状态");
                        consumCondition.await();
                       
    
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
    
                size-=1;
                System.out.println(Thread.currentThread().getName()+" 消费者消费了 "+1+" 个,总共还有 "+size);
                //唤醒生产者线程
                prodCondition.signal(); 
            }finally {
                lock.unlock();
            }
        }
    }

    运行结果(截取部分图)

    根据结果分析可以得出:
          生产者生产产品,当超过10个,生产者会处于等待状态,直到消费者消费者消费了一个产品,生产者才会重新唤醒。

     2、采用wait()和notifyAll()方法

     (1)仓库类代码(测试类代码不变)

    public class Depot {
       //初始仓库为0,最大为10,超过10生产者停止生产
        private int size;
        private int maxSize=10;
    
        public Depot(){
            this.size=0;
        }
    
        /*
         * 生产者生产方法
         */
        public synchronized void prod(){
    
            try{
              //如果生产超过max值,则生产者进入等待
                while(size+1>maxSize){
                    try {
                   //采用wait方法
                          wait();
                       System.out.println(Thread.currentThread().getName()+"生产者进入等待状态");         
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
    
                size+=1;        
                System.out.println(Thread.currentThread().getName()+" 生产了一个 "+1+" 总共还有 "+size);
                
                //唤醒所有线程
                 notifyAll();
             
            }finally {     
            }
        }
    
        /*
         * 消费者消费方法
         */
        public synchronized void consum(){
    
            try{
                //如果当前大小减去要消费的值,如果小于0的话,则进入等待
                while(size-1<0){
                    try {
                         wait();
                         System.out.println(Thread.currentThread().getName()+" 消费者进入等待状态");
                      
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
              
                size-=1;
                System.out.println(Thread.currentThread().getName()+" 消费者消费了 "+1+" 个,总共还有 "+size);
                //唤醒所有线程
                notifyAll();
              
            }finally {
            }
        }
    }    

    运行结果:

    对比:

           首先可以看出两个都可以实现生产者消费者的工作,不过可以发现Condition的signal相对于Object的notify最大有点就是它可以唤醒指定的线程,

    比如这里可以指定唤醒生产线程或者消费线程,而用notify是不能唤醒指定线程的,你只能通过notifyAll来唤醒所有。

     想太多,做太少,中间的落差就是烦恼。想没有烦恼,要么别想,要么多做。少校【14】

  • 相关阅读:
    cocos2dx 2.0 学习笔记简单动画
    几种插入数据的方法
    c#中如何获取本机用户名、MAC地址、IP地址、硬盘ID、CPU序列号、系统名称、物理内存
    C#高效编程改进C#代码的50个行之有效的办法摘抄笔记
    获取两个日期之间的每一天
    取SQL中某个字段的后两位
    该行已经属于另一个表 的解决办法
    一个实体对象不能由多个 IEntityChangeTracker 实例引用
    MVC返回JSON,IE下无法接收JSON,IE下JSON提示另存为
    entity framework DbContext Attach判断
  • 原文地址:https://www.cnblogs.com/qdhxhz/p/9206076.html
Copyright © 2020-2023  润新知