ReentrantLock等待通知机制Condition介绍
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步:
- 把当前线程封装为一个Node节点,把节点加入等待队列
- fullyRelease()方法,释放锁
- 用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;
}
- 从这段代码可以看到,signal()是唤醒等待队列中的第一个线程
- CAS更新节点状态
- 唤醒此节点代表的线程
如果要唤醒全部线程,可以调用signalAll()方法。如果想唤醒部分线程,可以实例化多个Condition配合使用。
ReentrantLock等待通知机制Condition介绍的更多相关文章
- 显式锁(四)Lock的等待通知机制Condition
任意一个Java对象,都拥有一组监视器方法(定义在根类Object上),主要包括:wait( ).wait(long timeout).notify().notifyAll()方法:这些方法与关 ...
- 12.详解Condition的await和signal等待通知机制
1.Condition简介 任何一个java对象都天然继承于Object类,在线程间实现通信的往往会应用到Object的几个方法,比如wait(),wait(long timeout),wait(lo ...
- 详解Condition的await和signal等待/通知机制
本人免费整理了Java高级资料,涵盖了Java.Redis.MongoDB.MySQL.Zookeeper.Spring Cloud.Dubbo高并发分布式等教程,一共30G,需要自己领取.传送门:h ...
- Java并发编程,Condition的await和signal等待通知机制
Condition简介 Object类是Java中所有类的父类, 在线程间实现通信的往往会应用到Object的几个方法: wait(),wait(long timeout),wait(long tim ...
- Java并发之等待/通知机制
目录 1 前言 1.1 先来段代码放松一下 2 Object wait()/notify() 2.1 一段入门代码 2.2 问题三连击 a.为什么官方说wait() 要放在while里面? b.为什么 ...
- 超强图文|并发编程【等待/通知机制】就是这个feel~
你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it well enough ...
- java多线程系列(三)---等待通知机制
等待通知机制 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理解 ...
- 【Java并发基础】使用“等待—通知”机制优化死锁中占用且等待解决方案
前言 在前篇介绍死锁的文章中,我们破坏等待占用且等待条件时,用了一个死循环来获取两个账本对象. // 一次性申请转出账户和转入账户,直到成功 while(!actr.apply(this, targe ...
- Java并发读书笔记:线程通信之等待通知机制
目录 synchronized 与 volatile 等待/通知机制 等待 通知 面试常问的几个问题 sleep方法和wait方法的区别 关于放弃对象监视器 在并发编程中,保证线程同步,从而实现线程之 ...
随机推荐
- PHP入门培训教程 PHP变量的使用
很多朋友在编写PHP程序的时候有时候对变量总有着不能确定的问题,而且也有很多问题就是因为变量的处理不当所造成的.这里兄弟连PHP培训 小编,就PHP变量系统说一下. PHP的变量分为全局变量与局部 ...
- Java大文件上传详解及实例代码
1,项目调研 因为需要研究下断点上传的问题.找了很久终于找到一个比较好的项目. 在GoogleCode上面,代码弄下来超级不方便,还是配置hosts才好,把代码重新上传到了github上面. http ...
- Java——动态绑定和多态
动态绑定是在执行期间(而不是编译期间)判断所用对象的实际类型,根据其实际的类型调用其相应的方法(确定选择哪个多态形式被调用). 首先是方法的参数是父类对象,传入子类对象是否可行 然后引出Parent ...
- malloc(50) 内存泄露 内存溢出 memory leak会最终会导致out of memory
https://en.wikipedia.org/wiki/Memory_leak In computer science, a memory leak is a type of resource l ...
- 织梦dedecms发布视频文章前台变成一张图片的解决方法
在发布文章的时候,有时需要插入视频的代码,如优酷.腾讯等视频,这样更能让文章变的丰富,但是在发布视频的时候,前台并不能播放视频,而是一张图片 解决这个方法其实很简单,在发布视频文章的时候,将附加选项的 ...
- java日期处理的一些例子使用...
一.计算成为会员多少天 需求:根据会员的创建日期createTime,计算成为会员多少天. 计算:当前日期 - 创建日期,转化为天数,即为成为会员多少天. 代码: public static void ...
- oracle 11g不能导出空表的解决方法
在oracle 11g r2中,发现传统的exp居然不能导出空的表,然后查询一下, 发现需要如下的步骤去搞,笔记之. oracle 11g 新增了一个参数:deferred_segment_c ...
- Powershell 邮件发送
目录 目录 前言 Send-MailMessage NETMail 使用OutLook发送邮件 前言 最近领导想在winServer2012上搞个自动发送邮件的计划任务,下面有几种发送邮件的方式. 如 ...
- 阶段1 语言基础+高级_1-2 -面向对象和封装_14private关键字的作用及使用
新建一个类Person代表人 创建demo03Person类去调用Person这个类 年龄设置为负数.虽然可以设置为负数.但是这个数值不合理 外部访问这个age就会报错 负数设置不进来.正数也设置不了 ...
- 新手解惑:nginx&php-fpm&fastcgi 是什么关系
首先,CGI是干嘛的?CGI是为了保证web server传递过来的数据是标准格式的,方便CGI程序的编写者. web server(比如说nginx)只是内容的分发者.比如,如果请求/index ...