最初想有没有必要写这类文章,网上相关的文章很多,有些更为透彻,自己再写一篇不免有重复造轮子的感觉。

但想想写文除了分享知识外也可以帮助自己总结归纳,也稍稍可以提高点自我满足感。


基本的线程阻塞原语,被用于创建锁和其他同步类上。

这个类的作用有点类似于Semaphore,通过许可证(permit)来联系使用它的线程。如果许可证可用,调用park方法会立即返回并在这个过程中消费这个许可,不然线程会阻塞。调用unpark会使许可证可用。(和Semaphores有些许区别,许可证不会累加,最多只有一张)

因为有了许可证,所以调用parkunpark的先后关系就不重要了,这里可以对比一下Object的waitnotify,如果先调用同一个对象的notifywait,那么调用wait的线程依旧会被阻塞,依赖方法的调用顺序。在一些场景下,LockSupport的方法都可以取代notifywait。举个简单的例子:

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();

可以先unparkpark,但如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浅析的更多相关文章

  1. 阻塞和唤醒线程——LockSupport功能简介及原理浅析

    目录 1.LockSupport功能简介 1.1 使用wait,notify阻塞唤醒线程 1.2 使用LockSupport阻塞唤醒线程 2. LockSupport的其他特色 2.1 可以先唤醒线程 ...

  2. ReentrantLock和condition源码浅析(二)

    转载请注明出处... 接着上一篇的ReentrantLock和condition源码浅析(一),这篇围绕着condition 一.condition的介绍 在这里为了作对比,引入Object类的两个方 ...

  3. JDK源码那些事儿之浅析Thread上篇

    JAVA中多线程的操作对于初学者而言是比较难理解的,其实联想到底层操作系统时我们可能会稍微明白些,对于程序而言最终都是硬件上运行二进制指令,然而,这些又太过底层,今天来看一下JAVA中的线程,浅析JD ...

  4. 关于 ReentrantLock 中锁 lock() 和解锁 unlock() 的底层原理浅析

    关于 ReentrantLock 中锁 lock() 和解锁 unlock() 的底层原理浅析 如下代码,当我们在使用 ReentrantLock 进行加锁和解锁时,底层到底是如何帮助我们进行控制的啦 ...

  5. SQL Server on Linux 理由浅析

    SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...

  6. 【深入浅出jQuery】源码浅析--整体架构

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  7. 高性能IO模型浅析

    高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking  ...

  8. netty5 HTTP协议栈浅析与实践

      一.说在前面的话 前段时间,工作上需要做一个针对视频质量的统计分析系统,各端(PC端.移动端和 WEB端)将视频质量数据放在一个 HTTP 请求中上报到服务器,服务器对数据进行解析.分拣后从不同的 ...

  9. Jvm 内存浅析 及 GC个人学习总结

    从诞生至今,20多年过去,Java至今仍是使用最为广泛的语言.这仰赖于Java提供的各种技术和特性,让开发人员能优雅的编写高效的程序.今天我们就来说说Java的一项基本但非常重要的技术内存管理 了解C ...

随机推荐

  1. web安全系列3:http拦截

    这是web安全系列第三篇,我们讲讲HTTP请求的拦截.关于http的内容请翻看我的上一篇文章. 首先,我们开始需要一个安装好的java环境,64位的.请自行安装和配置环境变量,如果遇到问题可以留言评论 ...

  2. loadrunner整体压测执行操作步骤

    lr11安装包链接:https://pan.baidu.com/s/1hF3j2Vi_xB8BhT70P1ZdBg 提取码:n3zn lr12安装包链接:https://pan.baidu.com/s ...

  3. redis学习-string常用命令

    keys * :查询所有的key值 set:为指定键设置对应的值 get:获取指定键的值 mset:一次传入多个键值对 mget:一次获取多个键的值 del:删除指定键 strlen:获取指定键值的长 ...

  4. abaqus修改inp直接建立工程

    前面已经知道,通过修改以下inp的节点和单元编号,就可以新建模型,可是对于大的工程来说,逐个选取单元进行添加材料以及确定哪步进行填土仍是比较麻烦的(如果工程网格划分好并告知哪些单元好属于哪些材料,哪些 ...

  5. metasploit渗透测试魔鬼训练营环境

    metasploitable winxpensp2 owasp_broken_web_apps win2k3 metasploitable 链接:https://pan.baidu.com/s/1oZ ...

  6. js实现全屏和缩放

    /** * @description 简单的浏览器检查结果. * `webkit` * webkit版本号,如果浏览器为非webkit内核,此属性为`undefined`. * `chrome` * ...

  7. 关于信息系统设计与开发——案例:VIP系统

    一.关于信息系统设计与开发 信息系统开发流程先对需求分析系统分析,设计数据库,设计程序,再对测试数据进行测试. 在程序设计中运用了接口:定义一个接口,可以有多种实现.变量声明为接口变量,调用接口方法, ...

  8. Eclipse项目里面看源码和文档

    Eclipse项目里面看源码 1.新建项目列表 2.进入struts2-core-2.3.20.jar,双击之后,看不到源码 3.右键struts2-core-2.3.20.jar,选择propert ...

  9. Python之旅Day12 HTML与CSS

    前端CSS与HTML部分 <a href="http://www.baidu.com" target="_Blank">百度</a>_B ...

  10. Linux下MySQL数据库的安装

    记录详细过程以备使用 1.创建群组及用户 obd:~ # groupadd mysql obd:~ # useradd -g mysql mysql 2.创建相关目录 obd:~ # mkdir -p ...