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 ...
随机推荐
- springcolud文章收藏
https://blog.csdn.net/dyc87112/column/info/14412https://blog.csdn.net/dyc87112/article/details/79357 ...
- 《Java并发编程的艺术》并发编程的挑战(一)
并发编程的挑战 并发编程的初衷是让程序运行的更快,但是更多的使用多线程真的会让程序变快吗? 1.线程上下文切换 关于线程上下文切换 多个线程在一个处理器里并不是同时进行的,而是非常快速地在线程之间进行 ...
- RT-thread-------------------信号量
信号量:用于解决线程间同步问题的内核对象,线程可以获取或释放它,从而达到同步或互斥的目的.(互斥量只能由持有线程释放,而信号量则可以由任何线程释放) 在rtt中,信号量分为计数型信号量和二值信号量(作 ...
- 加密 解密 RSA & AES & DES
git: https://github.com/XHTeng/XHCryptorTools rsa RSA加解密中必须考虑到的密钥长度.明文长度和密文长度问题.明文长度需要小于密钥长度,而密文长度则等 ...
- Java关键字this与super
this有两个用途: 1.引用隐式参数(出现在方法名前的参数,显示参数是出现在方法名后位于括号里的参数,如:e.raiseSalary(10%),e是隐式参数,10%是显示参数):这里比较常见.形式如 ...
- jQuery子页面获取父页面元素并绑定事件
父页面HTML文件: <ul id="faul"> <li class="sonli">子页面列表1</li> <li ...
- kali配置python3的开发环境
最近打算学习一下python3,毕竟不会写脚本的程序员,不是一个好的安全测试人员! 对于我来说,python的大部分应用都是在linux上,而kali是我唯一一个有图形化操作界面的linux系统 所以 ...
- logstash报错 :backtrace=>["org/jruby/RubyIO.java:1457:in `write'", "org/jruby/RubyIO.java:1428:in `write'"
报错: [2019-04-16T15:54:07,827][FATAL][logstash.runner ] An unexpected error occurred! {:error=>#&l ...
- SpringCloud服务注册与发现
1.介绍对于微服务的治理而言,其核心就是服务的注册和发现.在SpringCloud 中提供了多种服务注册与发现组件:Eureka,Consul,Zookeeper.官方推荐使用Eureka. 说明:E ...
- python之路(七)-递归算法
递归 特点 递归算法是一种直接或者间接地调用自身算法的过程.在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解. 递归算法解决问题的特点: (1) 递归就是在 ...