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. PHP基础教程 常见PHP错误类型及屏蔽方法

    程序只要在运行,就免不了会出现错误,错误很常见,比如Error,Notice,Warning等等.这篇文章兄弟连PHP培训 小编来跟大家具体说一下PHP的错误类型和屏蔽方法.在 PHP 中,主要有以下 ...

  2. 微信小程序支付功能讲解

    前言:虽然小程序做过很多,但是一直觉得微信支付功能很是神秘,现在终于有机会接触心里还是有点小激动的,经过一番折腾发现支付也不过如此,在此记录下支付功能的实现过程 小程序的官方文档介绍到发起微信支付即调 ...

  3. 2017南宁网络赛 Problem J Minimum Distance in a Star Graph ( 模拟 )

    题意 : 乱七八糟说了一大堆,实际上就是问你从一个序列到另个序列最少经过多少步的变化,每一次变化只能取序列的任意一个元素去和首元素互换 分析 : 由于只能和第一个元素去互换这种操作,所以没啥最优的特别 ...

  4. Codeforces 878A - Short Program(位运算)

    原题链接:http://codeforces.com/problemset/problem/878/A 题意:给出n个位运算操作, 化简这些操作, 使化简后的操作次数不多于5步. 思路:我们可以对二进 ...

  5. CodeForces 1198C 1199E Matching vs Independent Set

    Time limit 1000 ms Memory limit 262144 kB 这题是一场cf里,div1的第三题,div2的第5题 中文题意 给一张无向图,没说连通性,要你选出一个大小为n的匹配 ...

  6. 纯CSS手动滑动轮播图(隐藏滚动条)

    HTML: <div class="bigder"> <div class="big"> <dl> <dt>&l ...

  7. Spring Cloud架构教程 (五)服务网关(过滤器)

    过滤器的作用 通过上面所述的两篇我们,我们已经能够实现请求的路由功能,所以我们的微服务应用提供的接口就可以通过统一的API网关入口被客户端访问到了.但是,每个客户端用户请求微服务应用提供的接口时,它们 ...

  8. Java数据结构之单链表

    这篇文章主要讲解了通过java实现单链表的操作,一般我们开始学习链表的时候,都是使用C语言,C语言中我们可以通过结构体来定义节点,但是在Java中,我们没有结构体,我们使用的是通过类来定义我们所需要的 ...

  9. Codeforces Gym 100269 Dwarf Tower (最短路)

    题目连接: http://codeforces.com/gym/100269/attachments Description Little Vasya is playing a new game na ...

  10. postgresql批量删除表

    CREATE FUNCTION del_ora_table() RETURNS void AS $$ DECLARE tmp ); DECLARE names CURSOR FOR select ta ...