并发编程(五)LockSupport
并发编程(五)LockSupport
LockSupport 提供 park() 和 unpark() 方法实现阻塞线程和解除线程阻塞,实现的阻塞和解除阻塞是基于“许可(permit)”作为关联,permit 相当于一个信号量(0,1),默认是0。 线程之间不再需要一个 Object 或者其它变量来存储状态,不再需要关心对方的状态。
一、LockSupport API
(1) pack
| 方法 | 说明 |
|---|---|
| park() | 挂起当前线程 |
| park(Object blocker) | 挂起当前线程 |
| parkNanos(long nanos) | 指定挂起时间(相对于当前的时间),时间到后自动被唤醒 |
| parkNanos(Object blocker, long nanos) | 指定挂起时间(相对于当前的时间) |
| parkUntil(long deadline) | 指定挂起时间(绝对时间),时间到后自动被唤醒 |
| parkUntil(Object blocker, long deadline) | 指定挂起时间(绝对时间),时间到后自动被唤醒 |
从上面表格可以看出,park 支持 blocker 对象作为参数,该字段是 Thread 类,专门为 LockSupport 而设计的。此 blocker 对象在线程受阻塞时被记录,这样监视工具和诊断工具就可以确定线程受阻塞的原因。建议最好使用这些带 blocker 的方法版本,而不是不带 blocker 参数的方法。
public static void park() {
UNSAFE.park(false, 0L);
}
(2) unpark
设置线程许可为可用。
- 如果线程当前已经被 pack 挂起,那么这个线程将会被唤醒。
- 如果线程当前没有被挂起,那么下次调用 pack 不会挂起线程。
public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}
二、LockSupport 使用
(1) 先park后unpark
public void test1() throws Exception {
Thread mainThread = Thread.currentThread();
Thread thread = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("before unpark, " + LockSupport.getBlocker(mainThread));
LockSupport.unpark(mainThread);
System.out.println("after unpark, " + LockSupport.getBlocker(mainThread));
});
thread.start();
System.out.println("before park");
// 等待获取许可
LockSupport.park("Park");
System.out.println("after park");
}
结果:
before park
before unpark, Park
after park
after unpark, null
(2) 先unpark后unpark
先执行 unpark,在调用 park,直接就没被阻塞, 因此 park/unpark 相比 wait/notify 更加的灵活
public void test2() throws Exception {
Thread mainThread = Thread.currentThread();
Thread thread = new Thread(() -> {
System.out.println("before unpark, " + LockSupport.getBlocker(mainThread));
LockSupport.unpark(mainThread);
System.out.println("after unpark, " + LockSupport.getBlocker(mainThread));
});
thread.start();
TimeUnit.SECONDS.sleep(1);
System.out.println("before park");
// 等待获取许可
LockSupport.park("Park");
System.out.println("after park");
}
(2) park与interrupt
public void test3() throws Exception {
Thread thread = new Thread(() -> {
System.out.println(Thread.currentThread().isInterrupted()); // false
LockSupport.park();
System.out.println(Thread.currentThread().isInterrupted()); // true
});
thread.start();
TimeUnit.SECONDS.sleep(1);
thread.interrupt();
System.in.read();
}
简而言之:
- 实现机制和 wait/notify 有所不同,面向的是线程
- 不需要依赖监视器
- 与 wait/notify 没有交集
- 使用起来方便灵活
参考:
- 《LockSupport解析与使用》:https://blog.csdn.net/secsf/article/details/78560013
每天用心记录一点点。内容也许不重要,但习惯很重要!
并发编程(五)LockSupport的更多相关文章
- 【Java并发编程五】信号量
一.概述 技术信号量用来控制能够同时访问某特定资源的活动的数量,或者同时执行某一给定操作的数据.计数信号量可以用来实现资源池或者给一个容器限定边界. 信号量维护了一个许可集,许可的初始量通过构造函数传 ...
- Java并发编程 (五) 线程安全性
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 一.安全发布对象-发布与逸出 1.发布与逸出定义 发布对象 : 使一个对象能够被当前范围之外的代码所使用 ...
- 【Java并发编程实战】----- AQS(三):阻塞、唤醒:LockSupport
在上篇博客([Java并发编程实战]----- AQS(二):获取锁.释放锁)中提到,当一个线程加入到CLH队列中时,如果不是头节点是需要判断该节点是否需要挂起:在释放锁后,需要唤醒该线程的继任节点 ...
- 并发编程实践五:ReentrantLock
ReentrantLock是一个可重入的相互排斥锁,实现了接口Lock,和synchronized相比,它们提供了同样的功能.但ReentrantLock使用更灵活.功能更强大,也更复杂.这篇文章将为 ...
- 并发编程(十五)——定时器 ScheduledThreadPoolExecutor 实现原理与源码深度解析
在上一篇线程池的文章<并发编程(十一)—— Java 线程池 实现原理与源码深度解析(一)>中从ThreadPoolExecutor源码分析了其运行机制.限于篇幅,留下了Scheduled ...
- [Java并发编程(五)] Java volatile 的实现原理
[Java并发编程(五)] Java volatile 的实现原理 简介 在多线程并发编程中 synchronized 和 volatile 都扮演着重要的角色,volatile 是轻量级的 sync ...
- java高并发编程(五)线程池
摘自马士兵java并发编程 一.认识Executor.ExecutorService.Callable.Executors /** * 认识Executor */ package yxxy.c_026 ...
- Java并发编程原理与实战五:创建线程的多种方式
一.继承Thread类 public class Demo1 extends Thread { public Demo1(String name) { super(name); } @Override ...
- 并发编程概述 委托(delegate) 事件(event) .net core 2.0 event bus 一个简单的基于内存事件总线实现 .net core 基于NPOI 的excel导出类,支持自定义导出哪些字段 基于Ace Admin 的菜单栏实现 第五节:SignalR大杂烩(与MVC融合、全局的几个配置、跨域的应用、C/S程序充当Client和Server)
并发编程概述 前言 说实话,在我软件开发的头两年几乎不考虑并发编程,请求与响应把业务逻辑尽快完成一个星期的任务能两天完成绝不拖三天(剩下时间各种浪),根本不会考虑性能问题(能接受范围内).但随着工 ...
随机推荐
- js数组的初始化
方法一: var myarray = new Array(66,80,90,77,59); 方法二: var myarray = [66,80,90,77,59]; 方法三: var myarray= ...
- python对象转字典
1.基础实现 class TestDict: name = "wyb" age = " def __init__(self): self.gender = 'male' ...
- 如何使32位Win7支持超过4GB的内存,而不装64位
如何使32位Win7支持超过4GB的内存 让32位系统支持更大的内存超过4G [情况参数:] PC: 联想商用台式机,M4350 RAM: 1600, DDR3 , 2GB OS: Win7 专业版 ...
- openx _金额
1/work/openx/lib/max/Delivery/log.php MAX_Delivery_log_logAdImpression MAX_Delivery_log_logAdRequ ...
- HiveThrift
Hive具有一个可选的组件叫HiveServer或HiveThrift,其允许通过指定端口访问Hive.Thrift是一种软件架构,用于跨语言的服务开发. hive最常用的访问方式是采用cli访问,不 ...
- Eclipse中java文件和jsp字体大小设置
1.更改java文件大小设置Window->preferences->General->Appearance->Colors and Fonts->Java-&g ...
- XE6 HTML设计器
XE6 自带的HTML编辑器很好用 File>New>Other>Web Documents>HTML Page 自动有code和Design,在Design标签可以拖放控件 ...
- 5 并发编程-(进程)-队列&生产者消费者模型
1.队列的介绍 进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的 创建队列的类(底层就是以管道和锁定的方式实现 ...
- Nginx 错误汇总
1. Upstream timed out (110: Connection timed out) while reading response header from upstream 这种情况主要 ...
- LVS原理以及配置
安装好ipvsadm后需要查看内核是否加载了ip_vs模块儿,如果没有需要手动执行ipvsadm进行加载: # ipvsadm # lsmod |grep ip_vs # rmmod ip_vs_rr ...