欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

并发编程 - Condition

程序员文章站 2022-04-20 08:29:54
本文分析Condition的各个方法的作用,以及在AQS中对于该接口的实现。...


前言

Condition实现对线程的阻塞、唤醒。

阻塞和唤醒方法的调用需要在lock.lock()与lock.unlock()之间,在阻塞的过程中会释放同步状态。

与wait方式不同的是,它额外支持响应中断、截止时间等待。与notify随机唤醒线程方式不同的是,Condition支持特定线程唤醒(等待队列中队首线程)。

Condition是通过AQS中的Node节点来创建一条单向链表作为等待队列(条件队列)。调用await()方法,则向这条链表的尾部中添加节点。调用signal()方法,则从链表的头部删除一个节点,并把这个节点添加到同步队列中(删除队列头部的一个节点),节点进入同步队列中之后,则有机会争夺CPU时间片。

在一条线程中是有多个condition的,而一个condition则有一个等待队列。多个condition则有多条等待队列。则一条线程有多个等待队列。而wait和notify在一个线程中只能有一个等待队列。

e.g.

public class ConditionDemo implements Runnable {

    private static ReentrantLock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();

    @Override
    public void run() {
        try {
            lock.lock();
            condition.await();
            System.out.println("Thread continued to do something.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ConditionDemo demo = new ConditionDemo();
        Thread thread = new Thread(demo);
        thread.start();
        Thread.sleep(5000);
        lock.lock();
        condition.signal();
        lock.unlock();
    }
}

await

并发编程 - Condition

使当前线程等待,自动释放关联的锁,响应中断。

有如下四种方式进行唤醒:

  • 其他线程调用这个Condition关联的signal方法,当前线程恰好被选为被唤醒的线程。
  • 其他线程调用这个Condition关联的signalAll方法。
  • 其他线程中断了当前线程(支持线程中断)。
  • 发生虚假的唤醒(spurious wakeup)。

该方法调用的时候需要获取Condition关联的锁。被唤醒之后,也需要重新获取Condition关联的锁。


AQS#await

接下来看下AQS里对于该方法的实现:

并发编程 - Condition

  1. 判断是否线程中断。
  2. 将当前线程封装成一个condition状态的节点。然后在条件队列队尾进行添加。
  3. 释放同步状态。
  4. 判断节点是否在条件队列中。如果在,则一直阻塞等待。
  5. 等待的过程中响应中断,尝试将节点转移到同步队列中。
  6. 线程被唤醒之后,尝试获取锁。
  7. 对线程中断进行处理。

addConditionWaiter

并发编程 - Condition

将当前线程封装成一个condition状态的节点。然后在条件队列队尾进行添加。


并发编程 - Condition

在条件队列中取消非condition状态的节点的链接。

firstWaiter、lastWaiter标记条件队列中的头节点、尾节点。
方法中使用的trail变量:用于暂存上一个condition状态的节点。


fullyRelease

并发编程 - Condition

释放同步状态。


isOnSyncQueue

并发编程 - Condition

判断节点是否处于同步队列中。

prev、next在同步队列中指代前驱节点、后继节点。
而条件队列中使用的是nextWaiter,指代后继节点。

前驱节点不为空,后继节点为空,则调用如下方法查找判断。

并发编程 - Condition

从尾节点开始,判断给定节点是否在同步队列中。


checkInterruptWhileWaiting

并发编程 - Condition

在等待的过程中,检查是否中断。


并发编程 - Condition

尝试将节点转移到同步队列中。


reportInterruptAfterWait

并发编程 - Condition

根据interruptMode采取抛出异常,执行线程中断或者什么都不做。


awaitUninterruptibly

并发编程 - Condition

与await不同的是:线程一开始调用该方法以及等待的过程中不响应中断。等待过程结束后再去对中断进行处理。

AQS#awaitUninterruptibly

并发编程 - Condition


awaitNanos

并发编程 - Condition

超时等待。


await(…)

并发编程 - Condition

超时等待。


awaitUntil

并发编程 - Condition

超时等待。


signal

并发编程 - Condition

唤醒一个条件等待的线程。

调用该方法时,需要先获取condition关联的锁。


AQS#signal

并发编程 - Condition

并发编程 - Condition

唤醒条件队列中的队首节点。

并发编程 - Condition

将条件队列中的节点转移到同步队列中。唤醒线程。


signalAll

并发编程 - Condition

唤醒所有条件等待的线程。

调用该方法时,需要先获取condition关联的锁。


AQS#signalAll

并发编程 - Condition

并发编程 - Condition


本文地址:https://blog.csdn.net/qq_34561892/article/details/109338290

相关标签: 多线程