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

Condition介绍的更多相关文章

  1. ReentrantLock等待通知机制Condition介绍

    Object类中的wait(),notify()和notifyAll()可以实现线程的等待通知模型,同样在ReentrantLock中可以借助Condition来完成这种机制.本篇就简要介绍Condi ...

  2. java中Condition类的详细介绍(详解)

    已找不到原文了,还望原文博主看到能告诉小白一下,一定标注原文地址 一 condition 介绍及demo Condition是在java 1.5中才出现的,它用来替代传统的Object的wait(). ...

  3. Java多线程系列--“JUC锁”06之 Condition条件

    概要 前面对JUC包中的锁的原理进行了介绍,本章会JUC中对与锁经常配合使用的Condition进行介绍,内容包括:Condition介绍Condition函数列表Condition示例转载请注明出处 ...

  4. Java基础篇——线程、并发编程知识点全面介绍(面试、学习的必备索引)

    原创不易,如需转载,请注明出处https://www.cnblogs.com/baixianlong/p/10739579.html,希望大家多多支持!!! 一.线程基础 1.线程与进程 线程是指进程 ...

  5. Java - "JUC"之Condition源码解析

    Java多线程系列--“JUC锁”06之 Condition条件 概要 前面对JUC包中的锁的原理进行了介绍,本章会JUC中对与锁经常配合使用的Condition进行介绍,内容包括:Condition ...

  6. Condition接口

    <Java并发编程艺术>读书笔记 Condition介绍 任意一个Java对象,都拥有一组监视器方法(定义在java.lang.Object中),主要包括wait().wait(long ...

  7. Java多线程系列 JUC锁06 Condition条件

    Condition介绍 Condition中提供了一组类似于Object中的监视器方法.与Lock配合可以完成等待通知模式. Lock lock = new ReentrantLock(); Cond ...

  8. concurrent(四)Condition

    参考文档:Java多线程系列--“JUC锁”06之 Condition条件:http://www.cnblogs.com/skywang12345/p/3496716.html Condition介绍 ...

  9. Java锁--Condition

    转载请注明出处:http://www.cnblogs.com/skywang12345/p/3496716.html Condition介绍 Condition的作用是对锁进行更精确的控制.Condi ...

随机推荐

  1. Taurus.MVC V3.0.3 微服务开源框架发布:让.NET 架构在大并发的演进过程更简单。

    前方: 开源地址:https://github.com/cyq1162/Taurus.MVC 上篇文章介绍过:工业制造行业的低代码开发平台思维架构图 规划中涉及到了微服务,近些天经过努力和不断的代码与 ...

  2. react学习1-jsx语法注意点

    * 1.定义虚拟DOM不要写引号 * 2.标签中使用js表达式的时候,要使用{} * 3.样式类名指定要使用className * 4.要使用内联样式的话,要使用style={{key:"v ...

  3. 分享俩个js数组比较少用的方法join与from

    1:array.join 用于将数组中的所有元素转化为字符串 例: var arr = ["one", "two", "four"]; va ...

  4. 如何构建 Apache DolphinScheduler 的 Docker 镜像

    继昨日发布第一个 [官方 Docker 镜像] 后,有几位小伙伴私信想自己进行编译,这里也将 Docker 的主要贡献者文禾同学整理的文档进行分享.以下是全文内容: 您能够在类 Unix 系统和 Wi ...

  5. Taurus.MVC WebAPI 入门开发教程8:WebAPI文档与自动化测试。

    系列目录 1.Taurus.MVC WebAPI  入门开发教程1:框架下载环境配置与运行. 2.Taurus.MVC WebAPI 入门开发教程2:添加控制器输出Hello World. 3.Tau ...

  6. React报错之JSX element type does not have any construct or call signatures

    正文从这开始~ 总览 当我们试图将元素或react组件作为属性传递给另一个组件,但是属性的类型声明错误时,会产生"JSX element type does not have any con ...

  7. 60行自己动手写LockSupport是什么体验?

    60行自己动手写LockSupport是什么体验? 前言 在JDK当中给我们提供的各种并发工具当中,比如ReentrantLock等等工具的内部实现,经常会使用到一个工具,这个工具就是LockSupp ...

  8. Java SE 11 新增特性

    Java SE 11 新增特性 作者:Grey 原文地址:Java SE 11 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...

  9. 一文带你认知定时消息发布RocketMQ

    摘要:DMS任意时间定时消息能力发布. DMS是华为云的分布式消息中间件服务.适用于解决分布式架构中的系统解耦.跨系统跨地域数据流通.分布式事务协调等难题,协助构建优雅的现代化应用架构,提供可兼容 K ...

  10. ettercap之dns欺骗攻击

    前言:攻击机(kali)和受害机(win7)需在同一网段下 1.首先创建一个钓鱼克隆网站,这里我就利用CS来弄了 2.对Ettercap的dns文件进行编辑 3.开启ettercap 4.去受害机看看 ...