并发编程(五)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
每天用心记录一点点。内容也许不重要,但习惯很重要!