Condition 条件变量的使用

条件(也称为条件队列 或条件变量)为线程提供了一个含义,以便在某个状态条件现在可能为 true 的另一个线程通知它之前,一直挂起该线程(即让其“等待”)。因为访问此共享状态信息发生在不同的线程中,所以它必须受保护,因此要将某种形式的锁与该条件相关联。等待提供一个条件的主要属性是:以原子方式 释放相关的锁,并挂起当前线程,就像 Object.wait 做的那样



在Condition中,用await()替换wait(),用signal()替换notify(),用signalAll()替换notifyAll(),传统线程的通信方式,Condition都可以实现。
条件变量类似JDK1.4或以前版本中的 Object.wait(); Object.notify(); Object.notifyAll();
值得注意的是当condition.await()时,隐式的将条件变量关联的Lock解锁,而使其他线程有机会获得Lock,而检查条件,并在条件满足时,等待在条件变量上。

示例代码,ArrayBlockingQueue源码摘取:


    /** Main lock guarding all access */  
    private final ReentrantLock lock;  
    /** Condition for waiting takes */  
    private final Condition notEmpty;  
    /** Condition for waiting puts */  
    private final Condition notFull;  
    /** 
     * Inserts the specified element at the tail of this queue, waiting 
     * for space to become available if the queue is full. 
     * 
     * @throws InterruptedException {@inheritDoc} 
     * @throws NullPointerException {@inheritDoc} 
     */  
    public void put(E e) throws InterruptedException {  
     if (e == null) throw new NullPointerException();  
     final E[] items = this.items;  
     final ReentrantLock lock = this.lock;  
     lock.lockInterruptibly();  
     try {  
      try {  
       while (count == items.length)  
        notFull.await();  
      } catch (InterruptedException ie) {  
       notFull.signal(); // propagate to non-interrupted thread  
       throw ie;  
      }  
      insert(e);  
     } finally {  
      lock.unlock();  
     }  
    }  
    public E take() throws InterruptedException {  
     final ReentrantLock lock = this.lock;  
     lock.lockInterruptibly();  
     try {  
      try {  
       while (count == 0)  
        notEmpty.await();  
      } catch (InterruptedException ie) {  
       notEmpty.signal(); // propagate to non-interrupted thread  
       throw ie;  
      }  
      E x = extract();  
      return x;  
     } finally {  
      lock.unlock();  
     }  
    }  



有多个线程往里面存数据和从里面取数据,其队列(先进先出后进后出)能缓存的最大数值是capacity,多个线程间是互斥的,当缓存队列中存储的值达到capacity时,将写线程阻塞,并唤醒读线程,当缓存队列中存储的值为0时,将读线程阻塞,并唤醒写线程
这就是多个Condition的强大之处,假设缓存队列中已经存满,那么阻塞的肯定是写线程,唤醒的肯定是读线程,相反,阻塞的肯定是读线程,唤醒的肯定是写线程,那么假设只有一个Condition会有什么效果呢,缓存队列中已经存满,这个Lock不知道唤醒的是读线程还是写线程了,如果唤醒的是读线程,皆大欢喜,如果唤醒的是写线程,那么线程刚被唤醒,又被阻塞了,这时又去唤醒,这样就浪费了很多时间!


本篇非原创转自: http://cuisuqiang.iteye.com/blog/2019251

你可能感兴趣的:(thread)