2019独角兽企业重金招聘Python工程师标准>>>

Condition 接口

任意一个java对象,都拥有一组监视器方法,主要包括 wait(),wait(long timeout)、notify 以及 notifyAll 方法,这些方法与synchronized 同步关键字配合,可以实现等待/通知模式。Condition 接口也提供了类型Object的监视器方法,与Lock配合可以实现等待/通知模式。

condition 接口与示例

Condition 定义了等待/通知两种类型的方法,当前线程调用这些方法时,需要提前获取到Condition对象关联的锁。Condition对象由Lock对象(调用Lock对象的 newCondition方法)创建出来的。Condition是依赖Lock对象的。

package com.lock;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** Created by cxx on 2018/1/18.*/
public class ConditionOption {Lock lock = new ReentrantLock();Condition condition = lock.newCondition();public void conditonWait() throws InterruptedException{lock.lock();try {condition.await();}finally {lock.unlock();}}public void conditonSignal() throws InterruptedException{lock.lock();try {condition.signal();}finally {lock.unlock();}}}

获取一个Condition 必须通过Lock的newCondition() 方法。有界队列是一种特殊的队列,当队列为空时,队列的获取操作将会阻塞获取线程,直到队列中有新增元素,当队列已满时,队列的插入操作将会阻塞插入线程,知道队列出现“空位。”

package com.lock;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** Created by cxx on 2018/1/18.*/
public class BoundedQueue <T> {private Object[] items;private int addIndex,removeIndex,count;private Lock lock = new ReentrantLock();private Condition notEmpty = lock.newCondition();private Condition notFull = lock.newCondition();public BoundedQueue(int size){items = new Object[size];}//添加一个元素,如果数组满,则添加线程进入等待状态,直到有空位public void add(T t) throws InterruptedException{lock.lock();try {while (count == items.length){notFull.await();}items[addIndex] = t;if (++addIndex == items.length){addIndex = 0;}++count;notEmpty.signal();}finally {lock.unlock();}}//由头部删除一个元素,如果数组空,则删除线程进入等待状态,直到有添加元素。public T remove() throws InterruptedException{lock.lock();try {while (count == 0){notEmpty.await();}Object x = items[removeIndex];if (++removeIndex == items.length){removeIndex = 0;}--count;notFull.signal();return (T) x;}finally {lock.unlock();}}
}

在添加和删除方法中使用 while 循环而非 if判断,目的是防止过早或意外的通知,只有条件符合才能够退出循环。

Condition 的实现分析

ConditionObject 是同步器 AbstractQueuedSynchronizer的内部类,因为Condition的操作需要获取相关联的锁。每个Condition对象都包含着一个队列,该队列是Condition对象实现 等待/通知功能的关键。

等待队列

等待队列是一个FIFO的队列,在队列中的每个节点都包含了一个线程引用,该线程就是在Condition对象上等待的线程,如果一个线程调用了Condition.await()方法,那么该线程将会释放锁、构造成节点加入等待队列并进入等待状态。

一个Condition包含一个等待队列,Condition拥有首节点(firstWaiter)和尾节点(lastWaiter)。当前线程调用Condition.await()方法,将会以当前线程构造节点,并将节点从尾部加入等待队列。 Condition拥有首尾节点的引用,而新增节点只需要将原有的尾节点 nextWaiter 指向它,并且更新尾节点即可。上述节点应用更新的过程并没有使用CAS保证,原因在于调用 await()方法的线程必定是获取了锁的线程,这个过程是由锁来保证线程安全的。

在Object的监视器模型上,一个对象拥有一个同步队列和等待队列,而并发包中的Lock拥有一个同步队列和多个等待队列。

等待

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

    /*** Implements interruptible condition wait.* <ol>* <li> If current thread is interrupted, throw InterruptedException.* <li> Save lock state returned by {@link #getState}.* <li> Invoke {@link #release} with saved state as argument,*      throwing IllegalMonitorStateException if it fails.* <li> Block until signalled or interrupted.* <li> Reacquire by invoking specialized version of*      {@link #acquire} with saved state as argument.* <li> If interrupted while blocked in step 4, throw InterruptedException.* </ol>*/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 cancelledunlinkCancelledWaiters();if (interruptMode != 0)reportInterruptAfterWait(interruptMode);}

调用该方法的线程成功获取了锁的线程,也就是同步队列中的首节点,该方法将会当前线程构造成节点并加入等待队列中,然后释放同步状态,唤醒同步队列中的后继节点,然后当前线程会进入等待状态。

通知

调用 Condition的signal() 方法,将会唤醒在等待队列中等待时间最长的节点,在唤醒节点之前,会将节点移到同步队列中。

 /*** Moves the longest-waiting thread, if one exists, from the* wait queue for this condition to the wait queue for the* owning lock.** @throws IllegalMonitorStateException if {@link #isHeldExclusively}*         returns {@code false}*/public final void signal() {if (!isHeldExclusively())throw new IllegalMonitorStateException();Node first = firstWaiter;if (first != null)doSignal(first);}

调用该方法的前置条件是当前线程必须获取了锁,可以看到signal()方法进行了IsHeldExclusively()检查,也就是当前线程必须是获取了锁的线程,接着获取等待队列的首节点,将其移动到同步队列并使用LockSupport唤醒节点中的线程。

调用同步器的enq(Node node)方法,等待队列中的头节点线程安全地移动到同步队列。当节点移动到同步队列后,当前线程在使用LockSupport唤醒该节点的线程。

被唤醒后的线程,将从await()方法中的while循环中退出,进而调用同步器的acquireQueued()方法加入到获取同步状态的竞争中。

成功获取同步状态之后,被唤醒的线程就爱哪根葱先前调用的await()方法返回,此时该线程已经成功地获取了锁。

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

转载于:https://my.oschina.net/u/3421984/blog/1609338

Condition 接口相关推荐

  1. Condition接口详解

    一.condition和对象监视器 Condition是对象监视器的替代品,拓展了监视器的语义. 相同: 都有一组类似的方法: 对象监视器: Object.wait().Object.wait(lon ...

  2. newcondition java_Java并发Condition接口

    全屏 java.util.concurrent.locks.Condition接口提供一个线程挂起执行的能力,直到给定的条件为真. Condition对象必须绑定到Lock,并使用newConditi ...

  3. 多线程笔记补充之线程通信wait和notify方法以及Lock和Condition接口的使用

    线程通信-wait和notify方法介绍: java.lang.Object类提供类两类用于操作线程通信的方法. wait():执行该方法的线程对象释放同步锁,JVM把该线程存放到等待池中,等待其他的 ...

  4. Java并发编程——详解AQS对Condition接口的具体实现

    目录 一.等待/通知机制与Condition接口 1.1 等待/通知机制 1.2 Condition接口 二.AQS的具体实现 2.1 ConditionObject 2.2 等待机制 2.3 通知机 ...

  5. java condition原理_java中Condition接口原理及实现

    Condition是在java 1.5中才出现的,它用来替代传统的Object的wait().notify()实现线程间的协作,相比Object的wait().notify(),使用Condition ...

  6. @ConditionalOnBean、@ConditionalOnProperty、@ConditionalOnClass、@Conditional和Condition接口的使用

    一.@ConditionalOnBean.@ConditionalOnProperty.@ConditionalOnClass @ConditionalOnBean是指当spring容器中有某个bea ...

  7. Condition接口

    Condition wait().notify()与synchronized配合可以实现等待通知,condition和Lock配合同样也可以实现等待通知,但是两者之前还是有区别的. Condition ...

  8. Lock接口Condition,以及Lock与synchronized异同

    一.synchronized与Lock 基于synchronized关键字去实现同步的,(jvm内置锁,也叫隐式锁,由我们的jvm自动去加锁跟解锁的)juc下的基于Lock接口的这样的一种锁的实现方式 ...

  9. bean ref的bean可以做判断吗_Spring Boot @Condition 注解,组合条件你知道吗

    写在前面 当我们构建一个 Spring 应用的时候,有时我们想在满足指定条件的时候才将某个 bean 加载到应用上下文中, 在Spring 4.0 时代,我们可以通过 @Conditional 注解来 ...

最新文章

  1. 运算符优先级和结合性
  2. plsql developer导入导出序列方法
  3. CPU有个禁区,内核权限也无法进入!
  4. IDEA下maven工程找不到@Test
  5. 年终总结 | 从Oracle到MySQL大家最关注的竟然是...
  6. VC++获取文本框1内容在文本框2显示
  7. 在Android上可视化TensorFlow Lite AI结果
  8. 集合论——二元关系的定义组成及性质
  9. WCF学习之旅----基础篇之EnterpriseServices
  10. C语言输入中10A20B,C语言实验报告第3章答案.doc
  11. Regular Expression(正则表达式)之邮箱验证
  12. 精选免费可商用素材网站,包括PPT模板、PSD、矢量图等等
  13. 拼途网: 从线上到线下的拼途旅行社区
  14. js中函数传参的问题
  15. 以十年维度思考技术的发展
  16. 计算机上什么键有存储,电脑的保存快捷键是什么?电脑保存快捷键介绍
  17. VS2015官方下载地址(个人免费版)
  18. linux bootrom ftp,H3C交换机通过以太口应用ftp方式升级bootrom软件
  19. Circulation这篇文章帮你了解心脏最火的线粒体研究
  20. 福昕阅读器无法注释的解决

热门文章

  1. [Vue.js] 深入 -- 案例 - 购物车
  2. [jQuery基础] jQuery动效案例(二) -- 图标特效、无限循环滚动(简易轮播图)
  3. javascript基础系列:DOM相关的技术知识点
  4. easyPR源码解析之ann_train.h/config.h
  5. java报表的导出excel_java导出excel报表
  6. 7-5 精准运动 (10 分)
  7. 7-96 福到了 (15 分)
  8. 如何监测服务器网络稳定性centos,centos下网络监测工具nethogs
  9. matlab gui 二阶系统,实验二 二阶系统matlab仿真(dg).doc
  10. 部署Java web项目到阿里云服务器