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

  先看一下Condition的使用示例:

public class LockConditionTest {
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
/**
* 等待方法
*/
private void startAwait() {
try {
lock.lock();
System.out.println("开始等待:" + System.currentTimeMillis());
condition.await();
System.out.println("等待结束:" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
lock.unlock();
}
} /**
* 释放方法
*/
private void startSignal() {
try {
lock.lock();
System.out.println("开始释放");
condition.signal();
} catch (Exception e) {
e.printStackTrace();
}finally {
//这里锁被主线程持有,必须释放,让被唤醒的MyThread能够得到锁
lock.unlock();
}
} public static void main(String[] args) throws InterruptedException {
LockConditionTest test = new LockConditionTest();
MyThread myThread = new LockConditionTest().new MyThread(test);
//开始线程。 让线程等待。
myThread.start();
//myThread调用condition.await()释放锁,main线程开始执行
TimeUnit.MILLISECONDS.sleep();
//主线程唤醒等待线程
test.startSignal();
} class MyThread extends Thread{
private LockConditionTest test; public MyThread(LockConditionTest test) {
this.test = test;
} @Override
public void run() {
//开始等待,释放锁
test.startAwait();
}
} }

  这段代码的输出为:

开始等待:1550285191899
开始释放
等待结束:1550285192902

  等待时间大概为1000毫秒,符合预期。

  

下面看看Condition的await()方法:

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

  主要分为3步:

  1. 把当前线程封装为一个Node节点,把节点加入等待队列
  2. fullyRelease()方法,释放锁
  3. 用LockSupport.park()挂起当前线程

再看看signal()方法:

public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter; // 1
if (first != null)
doSignal(first);
} private void doSignal(Node first) {
do {
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, )) // 2
return false; Node p = enq(node);
int ws = p.waitStatus;
if (ws > || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread); // 3
return true;
}
  1. 从这段代码可以看到,signal()是唤醒等待队列中的第一个线程
  2. CAS更新节点状态
  3. 唤醒此节点代表的线程

  如果要唤醒全部线程,可以调用signalAll()方法。如果想唤醒部分线程,可以实例化多个Condition配合使用。

ReentrantLock等待通知机制Condition介绍的更多相关文章

  1. 显式锁(四)Lock的等待通知机制Condition

       任意一个Java对象,都拥有一组监视器方法(定义在根类Object上),主要包括:wait( ).wait(long timeout).notify().notifyAll()方法:这些方法与关 ...

  2. 12.详解Condition的await和signal等待通知机制

    1.Condition简介 任何一个java对象都天然继承于Object类,在线程间实现通信的往往会应用到Object的几个方法,比如wait(),wait(long timeout),wait(lo ...

  3. 详解Condition的await和signal等待/通知机制

    本人免费整理了Java高级资料,涵盖了Java.Redis.MongoDB.MySQL.Zookeeper.Spring Cloud.Dubbo高并发分布式等教程,一共30G,需要自己领取.传送门:h ...

  4. Java并发编程,Condition的await和signal等待通知机制

    Condition简介 Object类是Java中所有类的父类, 在线程间实现通信的往往会应用到Object的几个方法: wait(),wait(long timeout),wait(long tim ...

  5. Java并发之等待/通知机制

    目录 1 前言 1.1 先来段代码放松一下 2 Object wait()/notify() 2.1 一段入门代码 2.2 问题三连击 a.为什么官方说wait() 要放在while里面? b.为什么 ...

  6. 超强图文|并发编程【等待/通知机制】就是这个feel~

    你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it well enough ...

  7. java多线程系列(三)---等待通知机制

    等待通知机制 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理解 ...

  8. 【Java并发基础】使用“等待—通知”机制优化死锁中占用且等待解决方案

    前言 在前篇介绍死锁的文章中,我们破坏等待占用且等待条件时,用了一个死循环来获取两个账本对象. // 一次性申请转出账户和转入账户,直到成功 while(!actr.apply(this, targe ...

  9. Java并发读书笔记:线程通信之等待通知机制

    目录 synchronized 与 volatile 等待/通知机制 等待 通知 面试常问的几个问题 sleep方法和wait方法的区别 关于放弃对象监视器 在并发编程中,保证线程同步,从而实现线程之 ...

随机推荐

  1. mybatis insert update delete返回都是整型 0,1,增,删,改要提交事物

    mybatis insert update delete返回都是整型 0,1, 没有扔 增,删,改要提交事物

  2. github上.md的编写

    # algs4 一:大标题 =========== 二:中标题 ------------ 三:1~6级标题 # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题 ##### 五级标题 # ...

  3. Solr Windows环境安装配置

    在本章中,我们将讨论如何在Windows环境中设置Solr.要在Windows系统上安装Solr,需要按照以下步骤 - 访问Apache Solr的主页,然后点击下载按钮或直接访问:http://lu ...

  4. java导入ldif文件

    网上导入ldif文件的方式都是基于命令,或者相应工具如LDAP Browser \Editor v2.8.2. 但用java去实现这样的功能好像网上很少,于是我参照相应的开源代码并整理了一下,亲自测试 ...

  5. HDU6599 (字符串哈希+回文自动机)

    题意: 求有多少个回文串的前⌈len/2⌉个字符也是回文串.(两组解可重复)将这些回文串按长度分类,分别输出长度为1,2,...,n的合法串的数量. 题解:https://www.cnblogs.co ...

  6. HDU 5172 GTY's gay friends (线段树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5172 题意: 给你一个n个数的数组,m次询问,询问在[L, R] 这个区间里面有没有 [1, R-L+ ...

  7. 阶段1 语言基础+高级_1-3-Java语言高级_04-集合_02 泛型_6_泛型通配符

    泛型通配符是一个问号 也是代表不确定的意思 换成Object两个都报错了. 泛型是没有继承概念的,所以上面写Object就会报错.这里应问号 可以代表位置类型 it.next会自动用Object接收 ...

  8. 阶段1 语言基础+高级_1-3-Java语言高级_04-集合_06 Set集合_5_HashSet存储自定义类型元素

    想存储的元素不重复,就必须重写hashCode和equals这两个方法 新建一个Person类.添加姓名和年龄这两个成员变量..get和set,有参和无参构造. 重点是重写了toString的方法 自 ...

  9. delphi编写提取exe文件的ICO图标

    http://www.duote.com/tech/4/11797.html delphi编写提取exe文件的ICO图标 7.0分 出处:天下网吧 时间:2011-08-05 人气:2390 核心提示 ...

  10. B-/B+树 MySQL索引结构

    索引 索引的简介 简单来说,索引是一种数据结构 其目的在于提高查询效率 可以简单理解为“排好序的快速查找结构” 一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在中磁 ...