回顾前面部分的源码分析,当需要阻塞或唤醒一个线程的时候,都会使用LockSupport工具来完成相应工作。LockSupport定义了一组公共静态方法,这些方法提供了最基本的线程阻塞和唤醒公共,而LockSupport也成为构建同步组件的基础工具。
LockSupport定义了一组以park开头的方法用来阻塞当前线程,以及upark方法用来唤醒线程。这些方法如下所示:
方法名称 | 描述 |
---|---|
void park() | 阻塞当前线程,如果调用unpark(Thread)或者当前线程被中断,才能从park()方法返回 |
void parkNanos(long nanos) | 阻塞当前线程,最长不超过nanos纳秒,返回条件在park()的基础上增加了超时返回 |
void parkUntil(long deadline) | 阻塞当前线程,直到deadline |
void unpark(Thread thread) | 唤醒处于阻塞的线程thread |
在Java 6新增了void park(Object blocker)
, void parkNanos(Object blocker, long nanos)
, void parkUntil(Object blocker, long deadline)
三个方法,用以实现阻塞当前线程的功能,其中参数blocker是用来标识当前线程在在等待的对象(以下称阻塞对象),该对象主要用于问题排查和系统监控。
下面的示例中,将对比parkNanos(long nanos)
和parkNanos(Object blocker, long nanos)
方法来展示阻塞对象blocker的用处,代码片段和线程dump如下:
对比项\方法 | parkNanos(long nanos) | parkNanos(Object blocker, long nanos) |
---|---|---|
代码片段 | LockSupport.parkNanos(TimeUnit. SECONDS.toNanos(10)) |
LockSupport.parkNanos(test, TimeUnit.SECONDS.toNanos(10)); |
线程 dump 结果 |
"main" #1 prio=5 os_prio=0 tid= 0x0000025636fb9000 nid=0x1494 waiting on condition [0x000000bbe3fff000] java.lang.Thread.State: TIMED_WAITING (parking) at jdk.internal.misc.Unsafe.park (java.base@10.0.2/Native Method) at java.util.concurrent.locks.LockSupport. parkNanos(java.base@10.0.2/ LockSupport.java:357) |
"main" #1 prio=5 os_prio=0 tid=0x000002b0ceda8800 nid=0x724 waiting on condition [0x000000c6acafe000] java.lang.Thread.State: TIMED_WAITING (parking) at jdk.internal.misc.Unsafe.park(java.base @10.0.2/Native Method) - parking to wait for <0x00000006d119f9d8> (a p5.LockSupportTest) at java.util.concurrent.locks.LockSupport.parkNanos (java.base@10.0.2/LockSupport.java:234) |
从表中的线程dump结果可以看出,代码片段的内容是阻塞当前线程10s,但从线程dump结果可以看出,有阻塞对象的parkNanos方法能够传递给开发人员更多的线程信息。这是由于java 5之前,在线程阻塞(使用synchronized关键字)在一个对象上时,通过线程dump能够查看到该线程的阻塞对象,方便问题定位,而在java 5推出的Lock等并发工具时却遗漏了这一点,致使线程dump时无法提供阻塞对象的信息。因此,在java 6中,LockSupport新增了上述三个含有阻塞对象的park方法。
如果遗忘了如果进行线程dump操作,这里再温习一下。
运行测试方法(不一定是"main")后,在终端输入jps命令:
10964
2740 Launcher
9224 Program
12956 LockSupportTest
14300 KotlinCompileDaemon
7740 Jps
从中找到测试类对应的线程id,此处是 12956,然后终端输入jstack 12956,即可输出线程dump信息,然后从中寻找到对应测试方法的信息,此处为"main" #1 prio=5 os_prio=0 tid=0x0000025636fb9000 nid=0x1494 .....