天天看点

Java并发编程 - AQS 之 Condition

使用​

​ReentrantLock​

​​比直接使用​

​synchronized​

​​更安全,可以替代​

​synchronized​

​进行线程同步。

但是,​

​synchronized​

​​可以配合​

​wait​

​​和​

​notify​

​​实现线程在条件不满足时等待,条件满足时唤醒,用​

​ReentrantLock​

​​我们怎么编写​

​wait​

​​和​

​notify​

​的功能呢?

答案是使用​

​Condition​

​​对象来实现​

​wait​

​​和​

​notify​

​的功能。

我们仍然以​

​TaskQueue​

​​为例,把前面用​

​synchronized​

​​实现的功能通过​

​ReentrantLock​

​​和​

​Condition​

​来实现:

class TaskQueue {
    private final Lock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();
    private Queue<String> queue = new LinkedList<>();

    public void addTask(String s) {
        lock.lock();
        try {
            queue.add(s);
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public String getTask() {
        lock.lock();
        try {
            while (queue.isEmpty()) {
                condition.await();
            }
            return queue.remove();
        } finally {
            lock.unlock();
        }
    }
}      

可见,使用​

​Condition​

​​时,引用的​

​Condition​

​​对象必须从​

​Lock​

​​实例的​

​newCondition()​

​​返回,这样才能获得一个绑定了​

​Lock​

​​实例的​

​Condition​

​实例。

​Condition​

​​提供的​

​await()​

​​、​

​signal()​

​​、​

​signalAll()​

​​原理和​

​synchronized​

​​锁对象的​

​wait()​

​​、​

​notify()​

​​、​

​notifyAll()​

​是一致的,并且其行为也是一样的:

  • ​await()​

    ​会释放当前锁,进入等待状态;
  • ​signal()​

    ​会唤醒某个等待线程;
  • ​signalAll()​

    ​会唤醒所有等待线程;
  • 唤醒线程从​

    ​await()​

    ​返回后需要重新获得锁。

此外,和​

​tryLock()​

​​类似,​

​await()​

​​可以在等待指定时间后,如果还没有被其他线程通过​

​signal()​

​​或​

​signalAll()​

​唤醒,可以自己醒来:

if (condition.await(1, TimeUnit.SECOND)) {
    // 被其他线程唤醒
} else {
    // 指定时间内没有被其他线程唤醒
}      

可见,使用​

​Condition​

​​配合​

​Lock​

​,我们可以实现更灵活的线程同步。

小结

继续阅读