Java并发笔记 (12)--- Condition与LockSupport 剖析

文章目录

  • Condition
      • 1. Condition接口与示例
      • 2. Condition的实现方式
        • 1. 等待队列
        • 2. 等待
        • 3. 通知
      • 补充:LockSupport

Condition

任意一个Java对象,都拥有一组监视器方法(定义在java.lang.Object上),主要包括wait()wait(long timeout)notify()以及notifyAll()方法,这些方法与synchronized同步关键字配合,以实现等待/通知模式。

Condition接口也提供了类似Object的监视器方法,与Lock配合可以实等待/通知模式,但是这两者在使用方式以及功能特性上还是有差别的。

对比:

对比项 Object Monitor Methods Condition
前置条件 获取对象锁 调用Lock.lock()
调用Lock.newCondition() 获取Condition对象
调用方法 直接调用 直接调用
等待队列个数 一个 多个
当前线程释放锁进入等待状态 支持 支持
当前线程释放锁进入等待状态,在等待中不响应中断 支持 不支持
进入超时等待 支持 支持
进入等待状态到某个时间 不支持 支持
唤醒等待队列中的一个线程 支持 支持
唤醒全部线程 支持 支持

1. Condition接口与示例

直接上示例代码

Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void conditionWait() throws InterruptedException {
    lock.lock();
    try{
        condition.await();
    }finally {
        lock.unlock();
    }
}

如示例所示,一般都会将Condition对象作为成员变量。当调用await()方法后,当前线程会释放锁并在此等待,而其他线程调用Condition对象的signal()方法,通知当前线程后,当前线程才从await()方法返回,并且在返回前已经获取了锁。

Condition方法描述:

// 线程进入等待状态,直到被中断或者signal()
void await() throws InterruptedException;
// 进入等待状态,可以看出对中断不敏感
void awaitUninterruptibly();
// 进入等待直到 被中断、signal()、超时
long awaitNanos(long nanosTimeout) throws InterruptedException;
// 与上面相同
boolean await(long time, TimeUnit unit) throws InterruptedException;
// 进入等待直到 被中断、signal()、到某个时间点
boolean awaitUntil(Date deadline) throws InterruptedException;
// 唤醒线程
void signal();
void signalAll();

2. Condition的实现方式

ConditionObject是同步器AbstractQueuedSynchronizer的内部类,可以理解为在同步队列的基础上加了一个等待队列!

1. 等待队列

Java并发笔记 (12)--- Condition与LockSupport 剖析_第1张图片

等待队列结构如上图所示

注意:述节点引用更新的过程并没有使用CAS保证,原因在于调用await()方法的线程必定是获取了锁的线程,也就是说该过程是由锁来保证线程安全的。

我们下面通过一张图来看看Lock怎么拥有:同步队列和等待队列

Java并发笔记 (12)--- Condition与LockSupport 剖析_第2张图片

Condition的实现是同步器的内部类,因此每个Condition实例都能够访问同步器提供的方法,相当于每个Condition都拥有所属同步器的引用

2. 等待

调用Condition的await()方法,会使当前线程进入等待队列并释放锁,同时线程状态变为等待状态。当从await()方法返回时,当前线程一定获取了Condition相关联的锁。

下面看一下AQSConditionObject类中的await方法:

public final void await() throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    Node node = addConditionWaiter();
    // 释放同步状态
    int savedState = fullyRelease(node);
    int interruptMode = 0;
    while (!isOnSyncQueue(node)) {
        LockSupport.park(this);
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
    if (node.nextWaiter != null) // clean up if cancelled
        unlinkCancelledWaiters();
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}

当前线程加入Condition的等待队列的过程如下图:

Java并发笔记 (12)--- Condition与LockSupport 剖析_第3张图片

3. 通知

调用Condition的signal()方法,唤醒等待时间最长的节点,由上图可以看出等待时间最长的节点是首节点

下面给出 signal()源代码

public final void signal() {
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    Node first = firstWaiter;
    if (first != null)
        // 内部会使用LockSupport.unpark()来唤醒线程竞争同步状态
        doSignal(first);
}

signal()的过程就是将线程从waiting状态->blocked状态的过程

Java并发笔记 (12)--- Condition与LockSupport 剖析_第4张图片

Condition的signalAll()方法,相当于对等待队列中的每个节点均执行一次signal()方法,效果就是将等待队列中所有节点全部移动到同步队列中,并唤醒每个节点的线程。

补充:LockSupport

LockSupport定义了一组的公共静态方法,这些方法提供了最基本的线程阻塞和唤醒功能。

下面从源代码分析一下:

// 阻塞当前线程
public static void park(Object blocker) {
    Thread t = Thread.currentThread();
    setBlocker(t, blocker);
    UNSAFE.park(false, 0L);
    setBlocker(t, null);
}
// 阻塞当前线程 不超过 nanos时间
public static void parkNanos(Object blocker, long nanos) {
    if (nanos > 0) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        UNSAFE.park(false, nanos);
        setBlocker(t, null);
    }
}
// 阻塞线程至指定时间
public static void parkUntil(Object blocker, long deadline) {
    Thread t = Thread.currentThread();
    setBlocker(t, blocker);
    UNSAFE.park(true, deadline);
    setBlocker(t, null);
}

// 唤醒线程
public static void unpark(Thread thread) {
    if (thread != null)
        UNSAFE.unpark(thread);
}

你可能感兴趣的:(高并发,java,并发编程)