首页 > 其他分享 >Condition介绍

Condition介绍

时间:2022-08-20 10:11:25浏览次数:34  
标签:node Node 队列 介绍 线程 节点 Condition first

Condition

Condition是一种多线程通信工具,表示多线程下参与数据竞争的线程的一种状态,主要负责多线程环境下对线程的挂起和唤醒工作。

方法
// ========== 阻塞 ==========
// 造成当前线程在接到信号或被中断之前一直处于等待状态。
void await() throws InterruptedException; 
// 造成当前线程在接到信号之前一直处于等待状态。【注意:该方法对中断不敏感】。
void awaitUninterruptibly(); 
// 造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。
//返回值表示剩余时间,如果在`nanosTimeout` 之前唤醒,那么返回值 `= nanosTimeout - 消耗时间` ,
//如果返回值 `<= 0` ,则可以认定它已经超时了
long awaitNanos(long nanosTimeout) throws InterruptedException; 
// 造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。
boolean await(long time, TimeUnit unit) throws InterruptedException; 
// 造成当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态。
//如果没有到指定时间就被通知,则返回 true ,否则表示到了指定时间,返回返回 false 。
boolean awaitUntil(Date deadline) throws InterruptedException; 
// ========== 唤醒 ==========
 // 唤醒一个等待线程。该线程从等待方法返回前必须获得与Condition相关的锁。
void signal();
// 唤醒所有等待线程。能够从等待方法返回的线程必须获得与Condition相关的锁。
void signalAll(); 
原理

Condition 内部维护一个条件队列,在获取锁的情况下,线程调用 await,线程会被放置在条件队列中并被阻塞。直到调用 signal、signalAll 唤醒线程,此后线程唤醒,会放入到 AQS 的同步队列,参与争抢锁资源。
AQS是AbstractQueuedSynchronizer的简称,翻译过来就是抽象队列同步器.

await

调用condition.await()方法会使当前线程进入等待队列并释放锁,同时线程变为等待状态。当从await()方法返回时,一定是获得与condition相关联的锁。
此时AQS主要执行以下动作:
线程1把自己包装成节点,waitStatus设为CONDITION(-2),追加到ConditionObject中的条件队列(每个ConditionObject有一个自己的条件队列);
线程1释放锁,把state设置为0;
然后唤醒等待队列中head节点的下一个节点;

//await
public final void await() throws InterruptedException {
    // 1、线程如果中断,那么抛出异常
    if (Thread.interrupted())
        throw new InterruptedException();
    // 2、将当前线程包装成为一个Node节点,加入FIFO队列中
    Node node = addConditionWaiter();
    // 3、释放锁
    int savedState = fullyRelease(node);
    int interruptMode = 0;
    // 4、判断节点是否在同步队列(注意非Condition队列)中,如果没有,则挂起当前线程,因为该线程尚未具备数据竞争资格
    while (!isOnSyncQueue(node)) {
        // 5、挂起线程
        LockSupport.park(this);
        // 6、中断直接返回
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    // 7、参与数据竞争(非中断时执行)
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
        
    // 清理条件队列中状态为cancelled的节点
    if (node.nextWaiter != null) // clean up if cancelled
        unlinkCancelledWaiters();
    
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
    }
signal

另一个线程执行了 condition1.signal之后,主要是做了以下事情:
把条件队列中的第一个节点追加到等待队列中;
把等待队列原来尾节点的waitStatus设置为SIGNAL。
然后继续处理自己的事情,自己的事情处理完成之后,会释放锁,唤醒等待队列中head节点的下一个节点线程进行工作。

 public final void signal() {
 // 调用signal的线程必须持有独占锁
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            if (first != null)
                doSignal(first);
        }
                
 private void doSignal(Node first) {
            do {
    // 因为first马上就要被转移到同步队列了,所以将first.nextWaiter,作为新的firstWatier。
                if ( (firstWaiter = first.nextWaiter) == null)
                    lastWaiter = null;
                    //切断和等待队列的关联
                first.nextWaiter = null;
                                // 如果转移不成功且还有后续节点,那么继续后续节点的转移
            } while (!transferForSignal(first) &&
                     (first = firstWaiter) != null);
        }

final boolean transferForSignal(Node node) {
 
    // 判断节点是否已经在之前被取消了
    if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
        return false;

    // 调用 enq 添加到 同步队列的尾部
    Node p = enq(node);
    int ws = p.waitStatus;
    // node 的上一个节点 修改为 SIGNAL 这样后续就可以唤醒自己了
    if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
        LockSupport.unpark(node.thread);
    return true;
}

使用示例

public class LockConditionDemo {

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

    public static void main(String[] args) throws InterruptedException {
        Thread threadA = new Thread(() -> {
            System.out.println("threadA start");
            lock.lock();
            System.out.println("threadA getLock Running");
            try {
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.unlock();
            System.out.println("threadA end");
        });

        Thread threadB = new Thread(() -> {
            System.out.println("threadB start");
            lock.lock();
            System.out.println("threadB getLock Running");
            condition.signal();
            lock.unlock();
            System.out.println("threadB end");
        });

        threadA.start();
        TimeUnit.SECONDS.sleep(2);
        threadB.start();
    }
}
threadA start
threadA getLock Running
threadB start
threadB getLock Running
threadB end
threadA end

标签:node,Node,队列,介绍,线程,节点,Condition,first
From: https://www.cnblogs.com/gustavo/p/16607227.html

相关文章

  • ThreadLocal介绍
    介绍ThreadLocal是一个线程变量工具类,提供了线程局部变量,就是为每一个使用该变量的线程都提供一个变量值的副本。我们可以利用ThreadLocal创建只能由同一线程读和写的变量......
  • Rust实战系列-Rust介绍
    “学习资料:rustinaction[1]1.Rust安装curl--proto'=https'--tlsv1.2-sSfhttps://sh.rustup.rs|shsource"$HOME/.cargo/env"2.helloworld创建hel......
  • monodepth2学习1-原理介绍
    monodepth2介绍monodepth2是在2019年CVPR会议上提出的一种三维重建算法,monodepth2是基于monodepth进行了改进,采用的是基于自监督的神经网络,提出了一下三点优化:一个最小......
  • 逻辑分析仪的简单使用介绍(附带i2c、串口、spi数据分析)
    本次文章给大家介绍一种便宜好用的协议分析工具,逻辑分析仪,首先声明,小飞哥作这篇介绍文章,不是为了打广告哈,实在是因为这个小玩意很好用,有些小伙伴还不太清楚该如何使用!!!废话......
  • 易基因:原核转录组测序(mRNA+sRNA)技术介绍|技术推介
    大家好,这是专注表观组学十余年,领跑多组学科研服务的易基因。 原核转录组测序可以从基因表达量、基因结构和sRNA调控功能三维度揭示不同生物性状的分子调控机制。如通过......
  • ZAB协议介绍
    什么是Zab协议ZAB协议,全称ZookeeperAtomicBroadcast(Zookeeper原子广播协议)。它是专门为分布式协调服务——Zookeeper,设计的一种支持崩溃恢复和原子广播的协议。从设......
  • Angular forRoot 方法的使用场合介绍
    forRoot()方法返回一个NgModule及其提供者Providers依赖项。NgModuleforRoot()约定对Angular初学者来说是一个奇怪的约定:命名说明了如何使用它,但没有说明这样做......
  • Mybatis核心配置文件中的标签介绍
    0.标签顺序Mybatis核心配置文件中有很多标签,它们谁谁写在前写在后其实是......
  • 防抖和节流的介绍及实现
    防抖概述:在规定时间内只执行一次(执行最后一次)举个例子:电梯关门案例a进入电梯等待5s后就可以上升了在a等待了4s中后b过来那么之前的等待就结束了开始新的等待......
  • 关于!this.IsPostBack 使用介绍
    https://blog.csdn.net/panda_xingfu/article/details/9468695如果我们需要某些代码只需要执行一次,最好的选择当然是放在if(!this.IsPostBack){}里面.如果我们不写......