LockSupport浅析
最初想有没有必要写这类文章,网上相关的文章很多,有些更为透彻,自己再写一篇不免有重复造轮子的感觉。
但想想写文除了分享知识外也可以帮助自己总结归纳,也稍稍可以提高点自我满足感。
基本的线程阻塞原语,被用于创建锁和其他同步类上。
这个类的作用有点类似于Semaphore
,通过许可证(permit
)来联系使用它的线程。如果许可证可用,调用park
方法会立即返回并在这个过程中消费这个许可,不然线程会阻塞。调用unpark
会使许可证可用。(和Semaphores
有些许区别,许可证不会累加,最多只有一张)
因为有了许可证,所以调用park
和unpark
的先后关系就不重要了,这里可以对比一下Object的wait
和notify
,如果先调用同一个对象的notify
再wait
,那么调用wait
的线程依旧会被阻塞,依赖方法的调用顺序。在一些场景下,LockSupport
的方法都可以取代notify
和wait
。举个简单的例子:
final Object lock = new Object();
Thread t1 = new Thread() {
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock) {
lock.notifyAll();
}
};
};
Thread t2 = new Thread() {
public void run() {
synchronized (lock) {
try {
lock.wait();
System.out.println("I am alive");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
};
t1.start();
t2.start();
这段代码,只有确保t2先进入临界区并执行wait后才能正常打印内容。
换成LockSupport
就没有这种担心了。
Thread t2 = new Thread() {
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t2 end sleep");
LockSupport.park(this);
System.out.println("I am alive");
};
};
Thread t1 = new Thread() {
public void run() {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
LockSupport.unpark(t2);
System.out.println("I am done");
};
};
t1.start();
t2.start();
可以先unpark
再park
,但如API文档所说,unpark
需要传入的线程已经启动。在上述t1.start()
后用t1.join()
等方法在t2
启动前调用了unpark
就无效了。
但也不意味着wait
,notify
就没用了。wait
是调用对象的方法,和这个对象资源绑定,线程间不需要彼此感知到对方(能获取对方引用),只需要共有这个资源即可,另一方面LockSupport
可以指定unpark
的线程,这点也是前者无法做到的,两者间不能完全取代彼此。
park
方法也有可能在没有"任何理由"的情况下返回,所以通常要在一个循环中使用它并重新判断可以返回的条件。这一点和Object.wait
方法一样,可以参考wiki,大致可以理解为底层系统因为优化需要允许出现这样的情况,JVM的线程就是系统线程这种情况也无法避免。可以作为"忙等待"的优化,但是必须要注意要有配对的unpark方法。
使用模式如下:
while (!canProceed()) { ... LockSupport.park(this); }}
在提供的方法中可以看到有一组传入名为blocker对象作为参数的方法,记录这个对象可以方便许可证监视和诊断工具分析。
取上述代码,不启动t1的情况直接运行t2进入阻塞,jstack可以看到:
"Thread-0" #10 prio=5 os_prio=0 tid=0x000000001b586800 nid=0x37f0 waiting on condition [0x000000001c0ae000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000d603a6e8> (a test.TestLockSupport$1)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at test.TestLockSupport$1.run(TestLockSupport.java:21)
会将传入的对象打出。
更多资料:
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/LockSupport.html
http://agapple.iteye.com/blog/970055
http://blog.csdn.net/hengyunabc/article/details/28126139
LockSupport浅析的更多相关文章
- 阻塞和唤醒线程——LockSupport功能简介及原理浅析
目录 1.LockSupport功能简介 1.1 使用wait,notify阻塞唤醒线程 1.2 使用LockSupport阻塞唤醒线程 2. LockSupport的其他特色 2.1 可以先唤醒线程 ...
- ReentrantLock和condition源码浅析(二)
转载请注明出处... 接着上一篇的ReentrantLock和condition源码浅析(一),这篇围绕着condition 一.condition的介绍 在这里为了作对比,引入Object类的两个方 ...
- JDK源码那些事儿之浅析Thread上篇
JAVA中多线程的操作对于初学者而言是比较难理解的,其实联想到底层操作系统时我们可能会稍微明白些,对于程序而言最终都是硬件上运行二进制指令,然而,这些又太过底层,今天来看一下JAVA中的线程,浅析JD ...
- 关于 ReentrantLock 中锁 lock() 和解锁 unlock() 的底层原理浅析
关于 ReentrantLock 中锁 lock() 和解锁 unlock() 的底层原理浅析 如下代码,当我们在使用 ReentrantLock 进行加锁和解锁时,底层到底是如何帮助我们进行控制的啦 ...
- SQL Server on Linux 理由浅析
SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...
- 【深入浅出jQuery】源码浅析--整体架构
最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...
- 高性能IO模型浅析
高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking ...
- netty5 HTTP协议栈浅析与实践
一.说在前面的话 前段时间,工作上需要做一个针对视频质量的统计分析系统,各端(PC端.移动端和 WEB端)将视频质量数据放在一个 HTTP 请求中上报到服务器,服务器对数据进行解析.分拣后从不同的 ...
- Jvm 内存浅析 及 GC个人学习总结
从诞生至今,20多年过去,Java至今仍是使用最为广泛的语言.这仰赖于Java提供的各种技术和特性,让开发人员能优雅的编写高效的程序.今天我们就来说说Java的一项基本但非常重要的技术内存管理 了解C ...
随机推荐
- sha1 算法源码
原来指望sha1 这种烂大街的算法 不会出什么幺蛾子 结果<linux C编程实战Code>bt章节的sha1 代码 我在linux和windows下的结果不一样 然后用了哈希工具查看了下 ...
- 第二阶段第七次spring会议
昨天我将尝试对软件进行添加搜索引擎的界面. private void linkLabel1_LinkClicked_1(object sender, LinkLabelLinkClickedEvent ...
- MySql添加远程超级管理员用户
可以通过发出GRANT语句增加新用户:首先在数据库本机上用ROOT用户登录上MySql,然后运行命令: mysql>GRANT ALL PRIVILEGES ON *.* TO admin'@' ...
- 第九周助教工作总结——NWNU李泓毅
1.助教博客链接: https://www.cnblogs.com/NWNU-LHY/ 2.作业要求博客链接: https://www.cnblogs.com/nwnu-daizh/p/1072688 ...
- angular 实现 echarts 拖动区域进行放大 方法
实现逻辑: 1.通过鼠标摁下事件 和弹出事件 获取x轴的index 之后去x轴的list中去获取两个坐标点 2.之后将这两个数据作为参数 传到后台更新数据 3.记录下来这两个坐标点 放到lis ...
- MFC改变坐标系
1.在MainFrm中的PreCreateWindow中设置默认窗口大小 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { if( !C ...
- nginx server
配置nginx 首先apt install nginx 然后安装php apt-get install php7.0-fpm php7.0-mysql php7.0-common php7.0-mbs ...
- Day09 (黑客成长日记) 爬虫入门
爬虫的基本流程: 发起请求通过HTTP库向目标站点发起请求,也就是发送一个Request,请求可以包含额外的header等信息,等待服务器响应 获取响应内容如果服务器能正常响应,会得到一个Respon ...
- MySQL的计算时间差
一.MySQL计算两个日期的时间差 TIMESTAMPDIFF(DAY, datetime1, datetime2); 第一个参数为比较类型,有day, month, year, hour等: 第二个 ...
- HTML基本格式和文本元素(标签)介绍
<!doctype html>//声明文档类型 <html lang="zh-cn">//文档开始,后面是声明是中文页面的意思,en是英语的意思 <h ...