谢邀。不知道题中的一段文字出自何处。“锁池”和“等待池”这种翻译我还是头一回见。不过,题主的思路已经对了,即不拘泥于文字,而是在考虑这两个东西在锁的调度(即决定哪个线程可以获得锁的过程)中起到什么作用。

Java平台中,每个对象都有一个唯一与之对应的内部锁(Monitor)。Java虚拟机会为每个对象维护两个“队列”(姑且称之为“队列”,尽管它不一定符合数据结构上队列的“先进先出”原则):一个叫Entry Set(入口集),另外一个叫Wait Set(等待集)。对于任意的对象objectX,objectX的Entry Set用于存储等待获取objectX对应的内部锁的所有线程。objectX的Wait Set用于存储执行了objectX.wait()/wait(long)的线程。

设objectX是任意一个对象,monitorX是这个对象对应的内部锁,假设有线程A、B、C同时申请monitorX,那么由于任意一个时刻只有一个线程能够获得(占用/持有)这个锁,因此除了胜出(即获得了锁)的线程(这里假设是B)外,其他线程(这里就是A和C)都会被暂停(线程的生命周期状态会被调整为BLOCKED)。这些因申请锁而落选的线程就会被存入objectX对应的Entry Set(以下记为entrySetX)之中。当monitorX被其持有线程(这里就是B)释放时,entrySetX中的一个任意(注意是“任意”,而不一定是Entry Set中等待时间最长或者最短的)线程会被唤醒(即线程的生命周期状态变更为RUNNABLE)。这个被唤醒的线程会与其他活跃线程(即不处于Entry Set之中,且线程的生命周期状态为RUNNABLE的线程)再次抢占monitorX。这时,被唤醒的线程如果成功申请到monitorX,那么该线程就从entrySetX中移除。否则,被唤醒的线程仍然会停留在entrySetX,并再次被暂停,以等待下次申请锁的机会。

如果有个线程执行了objectX.wait(),那么该线程就会被暂停(线程的生命周期状态会被调整为WAITTING)并被存入objectX的Wait Set(以下记为waitSetX)之中。此时,该线程就被称为objectX的等待线程。当其他线程执行了objectX.notify()/notifyAll()时,waitSetX中的一个(或者多个,取决于被调用的是notify还是notifyAll方法)任意(注意是“任意”,而不一定是Entry Set中等待时间最长或者最短的)等待线程会被唤醒(线程的生命周期状态变更为RUNNABLE)。这些被唤醒的线程会与entrySetX中被唤醒的线程以及其他(可能的)活跃线程共同参与抢夺monitorX。如果其中一个被唤醒的等待线程成功申请到锁,那么该线程就会从waitSetX中移除。否则,这些被唤醒的线程仍然停留在waitSetX中,并再次被暂停,以等待下次申请锁的机会。

@刘方外

我理解调用对象的 notifyAll方法后,waitSet 上的线程都会加入到 entrySet 中的吧?在一个持有锁的线程释放锁后,应该只有 entrySet 队列的线程可能获取锁,那这个通知是 park 来实现的吗?是否有保证获取锁公平性的相关设置?

1、从Java虚拟机性能的角度来说,Java虚拟机没有必要在notifyAll调用之后“将Wait Set中的线程移入Entry Set”。首先,从一个“队列”移动到另外一个“队列”是有开销的,其次,虽然notifyAll调用后Wait Set中的多个线程会被唤醒,但是这些被唤醒的线程极端情况下可能没有任何一个能够获得锁(比如被其他活跃线程抢先下手了)或者即便可以获得锁也可能不能继续运行(比如这些等待线程所需的等待条件又再次不成立)。那么这个时候,这些等待线程仍然需要老老实实在wait set中待着。因此,如果notifyAll调用之后就将等待线程移出wait set会导致浪费(白白地进出“队列”)。这点可以参考显式锁的实现:

java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(Node, int)

/**

* Acquires in exclusive uninterruptible mode for thread already in

* queue. Used by condition wait methods as well as acquire.

*

* @param node the node

* @param arg the acquire argument

* @return {@code true} if interrupted while waiting

*/

final boolean acquireQueued(final Node node, int arg) {

boolean failed = true;

try {

boolean interrupted = false;

for (;;) {

final Node p = node.predecessor();

if (p == head && tryAcquire(arg)) {

setHead(node);

p.next = null; // help GC

failed = false;

return interrupted;

}

if (shouldParkAfterFailedAcquire(p, node) &&

parkAndCheckInterrupt())

interrupted = true;

}

} finally {

if (failed)

cancelAcquire(node);

}

}

从上面的代码可以看出,(使用显式锁时)被唤醒的线程获得锁(tryAcquire调用返回true)之后才被从wait set中移出(setHead调用)。

2、内部锁仅仅支持非公平锁调度。显式锁既支持公平锁又支持非公平锁。

LockSupport.park/upark是在jdk1.5开始引入的,显式锁的在实现线程的暂停和唤醒的时候会用到这个两个方法。而内部锁是在jdk1.5之前就已经存在的。

【参考资料】

1、黄文海.Java多线程编程实战指南(核心篇).电子工业出版社,2017

java设置等待锁的时间_java的锁池和等待池相关推荐

  1. Java设置短信间隔时间_Java实现短信验证码--设置发送间隔时间,以及有效时间(Java+Redis)...

    标签:url   control   operation   短信验证码   reg   cep   ppi   任务   用户 Java实现短信验证码--设置发送间隔时间,以及有效时间(Java+R ...

  2. java 获取三天前时间_java 获取前几天时间

    标签: java   获取前几天时间 一.toLocaleString()函数过时: //当前时间 Date endDate=new Date(); String endTime=endDate.to ...

  3. Java设置系统日期和时间

    需求:利用java实现设置系统的日期和时间 一.代码Demo1 package com.xu.demo.test;import java.io.IOException;public class Set ...

  4. java同步锁如何使用_java 同步锁(synchronized)的正确使用姿势

    关于线程安全,线程锁我们经常会用到,但你的使用姿势正确不,反正我用错了好长一段时间而不自知.所以有了这篇博客总结下线程锁的正确打开姿势 废话不说看例子 一,对整个方法进行加锁 1,对整个方法进行加锁, ...

  5. java设置字体大小和颜色_Java 设置Excel图表背景填充(颜色、图片填充)

    本文介绍通过Java程序来设置Excel图表背景填充的方法,填充时,可设置颜色填充或者加载图片填充:填充区域可设置整个图表区域或者绘图区域.设置方法参考以下内容. 使用工具:Free Spire.XL ...

  6. java设置标签艺术字体颜色_Java 在Word文档中添加艺术字

    与普通文字相比,艺术字更加美观有趣也更具有辨识度,常见于一些设计精美的杂志或宣传海报中.我们在日常工作中编辑Word文档时,也可以通过添加艺术字体来凸显文章的重点,美化页面排版.这篇文章将介绍如何使用 ...

  7. java设置器或访问器_java里面的构造器、设置器、访问器的作用

    java里面的构造器是一个与类同名的特殊的方法,称为构造方法,在创建类的对象时使用,用于对象初始化. 设置器是一个针对类的某个私有属性成员属性的有特殊命名要求的方法,发XXX属性,应为setXXX.主 ...

  8. java设置表格第一列长度_java 画pdf用itext调整表格宽度、自定义各个列宽的方法...

    ps:我用的版本是7.0.5 场景: 左侧第一列宽度不够,导致数据换行. table table = new table(new float[2]); new 一个table之后,setwidthpe ...

  9. java后台怎么获取系统时间_Java 后台获取当前时间

    Calendar c = Calendar.getInstance();//可以对每个时间域单独修改 int year = c.get(Calendar.YEAR); int month = c.ge ...

最新文章

  1. 1微秒等于多少皮秒_注册汽油贸易公司分享1升汽油等于多少公斤?
  2. 教你制作可以随身携带的FreeBSD系统[转]
  3. “CEPH浅析”系列之八——小结
  4. pyqt5中信号与槽的认识
  5. 十一届蓝桥杯国赛 本质上升序列-dp
  6. java原子更新类_Java内部具有原子更新的动态热交换环境
  7. 【今日CV 视觉论文速览】 13 Feb 2019
  8. 中山一院:华南第一综合性三甲医院的 IT 基础架构转型实践
  9. 函数信号发生器的设计与实现_北邮大二上电子电路基础实验报告
  10. android和手环传输数据,智能手环工作原理_智能手环是如何进行数据传输的 - 全文...
  11. 视频画面显示单位fps与Hz的区别
  12. ipencil 无法与iPad配对
  13. iOS时间戳与北京时间的转换
  14. h5 版活体检测、视频活体检测
  15. 云仓是如何运行的?如何一件代发的?
  16. 求华摄氏度100‘F对应下的摄氏温度
  17. scala学习之scala中一些集合的常用函数
  18. OpenCV对像素的操作
  19. 数据库中存储过程和触发器的区别是什么
  20. 【Shell】20天学会shell脚本命令(2)变量的详解

热门文章

  1. 飞秋(FeiQ)已在计算机技术的世界里沉浸了十年
  2. Python菜鸟之python入门
  3. BIC无代码绘制差异基因火山图
  4. tomcat6的项目能直接在tomcat7上用吗_极尽人性化的设计: 能“隐形”的笔记本电脑支架...
  5. P3383 【模板】线性筛素数
  6. 除了uni-app可以做app外,flutter更接近原生开发应用
  7. 相对路径和绝对路径_linux系统中的绝对路径和相对路径
  8. android 点击两次退出,Android实现点击两次返回键退出
  9. Vue第一部分(2): 数据的渲染
  10. 【ES10(2019)】Object.fromEntries()