前言

本文隶属于专栏《100个问题搞定Java并发》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!

本专栏目录结构和参考文献请见100个问题搞定Java并发

正文

LockSupport 是一个非常方便实用的线程阻塞工具,它可以在线程内任意位置让线程阻塞。

与 Thread.suspend() 方法相比,它弥补了由于 resume() 方法发生导致线程无法继续执行的情况。

关于 suspend 和 resume 请参考我的博客——线程的挂起(suspend)和继续执行(resume)是什么情况?

和 Object.wait() 方法相比,它不需要先获得某个对象的锁,也不会抛出 InterruptedException 异常

关于 wait 请参考我的博客——线程的等待(wait)和通知(notify)是什么情况?

LockSupport 的静态方法 park() 可以阻塞当前线程,类似的还有 parkNanos() 、 parkUntil() 等方法。

它们实现了一个限时的等待。

对比

为了更好的将 LockSupport 和 suspend 进行对比,这里我们举一个例子。

suspend

下面的代码中 suspend 方法将导致线程卡死。

package com.shockang.study.java.concurrent.thread.suspend;public class SuspendDemo {public static Object u = new Object();static ChangeObjectThread t1 = new ChangeObjectThread("t1");static ChangeObjectThread t2 = new ChangeObjectThread("t2");public static class ChangeObjectThread extends Thread {public ChangeObjectThread(String name){super.setName(name);}@Overridepublic void run() {synchronized (u) {System.out.println("in "+getName());Thread.currentThread().suspend();}}}public static void main(String[] args) throws InterruptedException {t1.start();Thread.sleep(100);t2.start();t1.resume();t2.resume();t1.join();t2.join();}
}

LockSupport

现在用 LockSupport 重写这个程序:

package com.shockang.study.java.concurrent.lock;import java.util.concurrent.locks.LockSupport;public class LockSupportDemo {private static Object u = new Object();static ChangeObjectThread t1 = new ChangeObjectThread("t1");static ChangeObjectThread t2 = new ChangeObjectThread("t2");public static class ChangeObjectThread extends Thread {public ChangeObjectThread(String name) {super.setName(name);}@Overridepublic void run() {synchronized (u) {System.out.println("in " + getName());LockSupport.park();}}}public static void main(String[] args) throws InterruptedException {t1.start();Thread.sleep(100);t2.start();LockSupport.unpark(t1);LockSupport.unpark(t2);t1.join();t2.join();}
}

注意,这里只是将原来的 suspend 方法和 resume() 方法用 park() 方法和 unpark() 方法做了替换。

当然,我们依然无法保证 unpark() 方法发生在 park() 方法之后。

但是执行这段代码,你会发现,它自始至终都可以正常地结束,不会因为 park() 方法而导致线程水久挂起。

这是因为 LockSupport 类使用类似信号量的机制。

它为每一个线程准备了一个许可,如果许可可用,那么 park() 方法会立即返回,并且消费这个许可(也就是将许可变为不可用)。

如果许可不可用,就会阻塞,而 unpack 方法则使得一个许可变为可用(但是和信号量不同的是,许可不能累加,你不可能拥有超过一个许可,它永远只有一个)。

这个特点使得:即使 unpack() 方法操作发生在 park() 方法之前,它也可以使下一次的 park() 方法操作立即返回。

这也就是上述代码可顺利结束的主要原因。

线程状态 WAITING (parking)

同时,处于 parko 方法挂起状态的线程不会像 suspend 方法那样还给出一个令人费解的 Runnable 状态。

它会非常明确地给出一个 WAITING 状态,甚至还会标注是 park() 方法引起的。

这使得分析问题时格外方便。

"t1" #8 prio=5 os_prio=0 tid=0x00b1a400 nid=0x1994 waiting on condition [0x1619f000]java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) at java.util..concurrent.locks..LockSupport.park(LockSupport.java: 304) at com.shockang.study.java.concurrent.lock.LockSupportDemo$ChangeObjectThread.run(LockSupportDemo.java: 19) - locked <0x048b2680> (a java.lang.Object)

此外,如果你使用 park(Object)函数,那么还可以为当前线程设置一个阻塞对象。

这个阻塞对象会出现在线程 Dump 中。

这样在分析问题时,就更加方便了。

比如,我们将上述代码第 14 行的 park() 方法改为

LockSupport.park(this);

那么在线程 Dump 时,你可能会看到如下信息:

"t1" #8 prio=5 os_prio=0 tid=0x0117ac00 nid=0x2034 waiting on condition [0x15d0f000]java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x048b4738> (a com.shockang.study.java.concurrent.lock.LockSupportDemo$ChangeObjectThrea)at java.util..concurrent.locks..LockSupport.park(LockSupport.java: 304) at com.shockang.study.java.concurrent.lock.LockSupportDemo$ChangeObjectThread.run(LockSupportDemo.java: 19) - locked <0x048b2808> (a java.lang.Object)

注意,在堆栈中,我们甚至还看到了当前线程等待的对象,这里就是 ChangeObjectThread 实例

支持中断

除了有定时阻塞的功能, LockSupport.park() 方法还能支持中断影响。

但是和其他接收中断的函数很不一样, LockSupport.park() 方法不会抛出 InterruptedException 异常

它只会默默返回,但是我们可以从 Thread.interrupted() 等方法中获得中断标记。

代码

package com.shockang.study.java.concurrent.lock;import java.util.concurrent.locks.LockSupport;public class LockSupportIntDemo {private static Object u = new Object();static ChangeObjectThread t1 = new ChangeObjectThread("t1");static ChangeObjectThread t2 = new ChangeObjectThread("t2");public static class ChangeObjectThread extends Thread {public ChangeObjectThread(String name) {super.setName(name);}@Overridepublic void run() {synchronized (u) {System.out.println("in " + getName());LockSupport.park();if (Thread.interrupted()) {System.out.println(getName() + " 被中断了");}}System.out.println(getName() + "执行结束");}}public static void main(String[] args) throws InterruptedException {t1.start();Thread.sleep(100);t2.start();t1.interrupt();LockSupport.unpark(t2);}
}

控制台

in t1
t1 被中断了
t1执行结束
in t2
t2执行结束

LockSupport 是什么?怎么用?相关推荐

  1. 深入学习Lock锁(2)——LockSupport工具类

    2019独角兽企业重金招聘Python工程师标准>>> 在同步组件中,当需要阻塞或唤醒一个线程的时候,都会使用LockSupport工具类来完成相应 工作.LockSupport定义 ...

  2. LockSupport 使用

    使用: package com.xinyu.test;import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.L ...

  3. Java并发编程 LockSupport源码分析

    这个类比较简单,是一个静态类,不需要实例化直接使用,底层是通过java未开源的Unsafe直接调用底层操作系统来完成对线程的阻塞. 1 package java.util.concurrent.loc ...

  4. Java高并发编程(七):读写锁、LockSupport、Condition

    读写锁定义:读写锁在同一时刻可以允许多个读线程访问,但是在写线程访问时,所有的读 线程和其他写线程均被阻塞.读写锁维护了一对锁,一个读锁和一个写锁,通过分离读锁和写锁,使得并发性相比一般的排他锁有了很 ...

  5. java中的locksupport_详解Java多线程编程中LockSupport

    LockSupport是用来创建锁和其他同步类的基本线程阻塞原语. LockSupport中的park() 和 unpark() 的作用分别是阻塞线程和解除阻塞线程,而且park()和unpark() ...

  6. AQS理解之一,基础知识——LockSupport

    AQS理解之一,基础知识--LockSupport LockSupport类位于java.util.concurrent包下. 顾名思义,就是一个实现锁的辅助类. 来看下他的类结构: 其中的变量都是通 ...

  7. LockSupport

    LockSupport类是Java6引入的一个类,提供了基本的线程同步原语.LockSupport实际上是调用了Unsafe类里的函数,归结到Unsafe里,只有两个函数 unpark函数为线程提供& ...

  8. Java线程阻塞原语-LockSupport

    在Java6引入LockSupport以前,线程挂起和唤醒要通过Object的wait和notify/notifyAllfangAll实现,但后者必须要在同步块里调用,且notify必须要在wait之 ...

  9. 多线程与高并发(四):LockSupport,高频面试题,AQS源码,以及源码阅读方法论

    补充几道面试题 锁升级过程:无锁.偏向锁.轻量级锁.重量级锁 StampedLock 自己看一下 面试题:syn和Reentrantlock的区别? LockSupport LockSupport.p ...

  10. JUC锁-LockSupport(四)

    LockSupport的介绍 LockSupport是用来创建锁和其他同步类的基本线程阻塞原语. LockSupport中的park() 和 unpark() 的作用分别是阻塞线程和解除阻塞线程,而且 ...

最新文章

  1. Python中的反射机制(reflect)
  2. php和python哪个用了开发web好-php web与python web哪个好
  3. 传智播客视频学习 ---- 字符串含义( C 语言中)
  4. 郑州5月份的windows phone7小聚
  5. SynchronousQueue队列
  6. C++新增头文件.h,静态库.lib
  7. Ansible管理节点过多导致的超时问题解决方法
  8. 一文看懂集群、分布式与负载均衡的关系
  9. JavaOne 2015:高级模块化开发
  10. 数仓中的星型模型和雪花模型
  11. c语言删除结点,C语言在链表中删除结点
  12. netlink 学习笔记 3.8.13内核
  13. 大数据有哪些特点和作用
  14. 设计模式---模板模式(C++实现)
  15. 背水一战 Windows 10 (53) - 控件(集合类): ItemsControl 的布局控件 - ItemsStackPanel, ItemsWrapGrid...
  16. 字符常量与字符串常量
  17. 【Unity3D插件】MiniMap插件分享《小地图插件》
  18. fcpx插件:去除音频中的回声混响插件 EchoRemover
  19. [转]DSP2812 代码段(.text段)太长的解决办法——通过cmd文件拆分.text段
  20. sshv2 mitm工具jmitm2的使用记录

热门文章

  1. Java数组初始化, 冒泡排序, 查找
  2. 个人开发者如何免费打造属于自己的微信小程序
  3. SAM数据格式学习1之CIGAR理解
  4. PHP易联云打印机实现打印小票
  5. 我的北京生活,2018面向新的开始
  6. 台式计算机强制关机,台式电脑强制关机按什么键
  7. Linux手动安装JDK并配置多个版本JDK--JDK配置和Jenv的配置使用
  8. android开发笔记之2012版辅助开发工具包(ADT)新功能特性介绍及安装使用
  9. 春运浙江运送旅客量将达1.38亿人次 同比下降3.4%
  10. win7做服务器性能如何,win7如何做服务器配置