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. pandas中的describe方法

  2. 修改docker默认网段

    一. 修改普通docker run启动的容器的网段 https://blog.51cto.com/13670314/2345518?source=dra https://blog.csdn.net/w ...

  3. Netty 系列之 Netty 高性能之道 高性能的三个主题 Netty使得开发者能够轻松地接受大量打开的套接字 Java 序列化

    Netty系列之Netty高性能之道 https://www.infoq.cn/article/netty-high-performance 李林锋 2014 年 5 月 29 日 话题:性能调优语言 ...

  4. 了解SELlinux

    selinux是mac: mandatory access control. 强制访问控制. 是经过了20年的mac研究基础上开发的安全子系统. 访问控制分为三种: dac: di'scretiona ...

  5. php对bom的处理

    通常只有在windows的notepad中 , 创建文本文件, 保存为UTF-8 时, 它会自动添加3个字节: ef bb bf. 用editplus来看txt文件就可以看得很清楚. 但是, 只有wi ...

  6. 使用spring配置类代替xml配置文件注册bean类

    spring配置类,即在类上加@Configuration注解,使用这种配置类来注册bean,效果与xml文件是完全一样的,只是创建springIOC容器的方式不同: //通过xml文件创建sprin ...

  7. QCOW2/RAW/qemu-img 概念浅析

    目录 目录 扩展阅读 RAW QCOW2 QEMU-COW 2 QCOW2 Header QCOW2 的 COW 特性 QCOW2 的快照 qemu-img 的基本使用 RAW 与 QCOW2 的区别 ...

  8. 阶段1 语言基础+高级_1-3-Java语言高级_1-常用API_1_第5节 String类_10_练习:统计输入的字符串中

    char类型在发生数学运算的时候,可以提升为int类型 这就表示char在A到Z之间的

  9. 类Runtime

    Runtime类的概述和使用 Runtime类概述 每个Java应用程序都有一个Runtime类实例,使应用程序能够与其运行的环境相连接.可以通过getRuntime方法获取当前运行时. 应用程序不能 ...

  10. Postman Tests脚本的使用

    直接在Tests中写js代码断言结果,Test Result展示运行结果,简单方便. 示例脚本: var jsonData = JSON.parse(responseBody); var num = ...