Condition源码分析

Condition接口

概述

condition与Lock的实现类结合使用。 如果Lock替换了synchronized方法和语句的使用,则Condition将替换Object监视方法(wait,notify和notifyAll)的使用。

condition,也称为condition queue或者condition variables,能让一个线程阻塞在条件变量上,直到其他线程通知该线程条件变量现在可能为true。当一个线程等待条件时,它会自动释放相关联的锁,并陷入阻塞状态,就跟Object.wait()方法一样。

一个Condition实例一个Lock实例绑定,要获取特定Lock实例的Condition实例,可以调用Lock实例的newCondition()方法。

以生产者/消费者模式为例,假设我们有一个有界缓冲区,它支持put和take方法。 如果缓冲区为空,则消费线程将阻塞,直到缓冲区有内容为止; 如果缓冲区已满,则生产线程阻塞,直到缓冲区有空间可用为止。 我们希望把put线程和take线程放在不同的waitset中,以便我们在缓冲区中的内容可用或空间可用时,实现只通知一个线程。 这可以使用两个Condition实例来实现。

 class BoundedBuffer {
   final Lock lock = new ReentrantLock();
   final Condition notFull  = lock.newCondition(); 
   final Condition notEmpty = lock.newCondition(); 

   final Object[] items = new Object[100];
   int putptr, takeptr, count;

   public void put(Object x) throws InterruptedException {
     lock.lock();
     try {
       while (count == items.length)
         notFull.await();
       items[putptr] = x;
       if (++putptr == items.length) putptr = 0;
       ++count;
       notEmpty.signal();
     } finally {
       lock.unlock();
     }
   }

   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0)
         notEmpty.await();
       Object x = items[takeptr];
       if (++takeptr == items.length) takeptr = 0;
       --count;
       notFull.signal();
       return x;
     } finally {
       lock.unlock();
     }
   }
 }
 

Condition实现类提供与Object监视器方法不同的行为和语义,例如在waitset中阻塞等待时可以不响应中断,多个waitset。

在等待条件时,虚假唤醒是可以发生的。因此应用程序的程序员应该编写循环,在循环中等待条件。

等待条件有以下三种形式:

1、不可中断:void awaitUninterruptibly();

2、可中断:void await() throws InterruptedException;

3、定时: long awaitNanos(long nanosTimeout) throws InterruptedException;   返回值表示当前剩余的时间。

await()方法

await方法使当前线程阻塞等待,直到被通知或者被中断。

与该condition关联的lock会被自动释放,并且由于线程调度的原因线程变得不可用,直到以下情形之一发生:

1、其他线程调用了这个condition的signal()方法,并且当前线程被选为唤醒的线程;
2、其他线程调用了这个condition的signalAll()方法;
3、其他线程调用当前线程的Thread.interrupt()方法;
4、一个虚假唤醒发生时;

以上所有情形中,当前线程都必须重新获得与该condition关联的lock,才能从await方法返回。

如果当前线程在阻塞等待时被中断,将会抛出 InterruptedException,并清除中断状态。

signal()方法

唤醒等待线程。

如果存在线程在条件上等待,选择其中一个作为被唤醒的线程。

在调用该方法时,要求当前线程持有与condition关联的Lock。否则抛出IllegalMonitorStateException。

ConditionObject

ConditionObject是Condition在java并发中的具体实现,它是AQS的内部类。因为Condition相关操作都需要获取锁,所以作为AQS的内部类很合理。

猜你喜欢

转载自blog.csdn.net/qq_26222859/article/details/81131865