月泉的博客

JUC-LockSupport

字数统计: 1k阅读时长: 4 min
2018/11/04 Share

LockSupport是什么

LockSupport类是一个常用的用来实现锁或使一个线程阻塞的工具类(通常用来实现这些,当然有其它用途也可以的,只是个工具类而已),它主要提供了2个方法

  • park
  • unpark

park

阻塞当前线程并阻止该线程参与调度,除非其关联了许可证

unpark

给线程关联一个许可证(令它恢复线程调度)

小结

乍一看,其实parkunpark非常类似于waitnotify,那么既然有waitnotify了那么为什么还要在写一个和它类似功能的东西出来?其实只是类似而已,使用waitnotify你必须得先获取到监视器锁才能够使用否则将会抛出IllegalMonitorStateException而使用parkunpark不需要先获得监视器锁才能用。

其底层基本都是使用Unsafe类中的方法来实现的,而Unsafe中的方法都是native方法,而naive方法是由虚拟机层面上去做的实现,所以本文不对其背后的原理机制做描述(PS:虽然违背了我一贯的习惯,但是以后可能会写一下背后的原理吧。)

LockSupport怎么用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) {
Thread threadA = new Thread(() -> {
System.out.println("The thread will pack");
LockSupport.park(); // 1
System.out.println("The thread packed");
});
threadA.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
LockSupport.unpark(threadA); //2
}

1处调用后线程将会被阻塞,等到2处调用时恢复线程调度,等待调度执行

那么再来看一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void main(String[] args) {
Thread threadA = new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("The thread sleeped");
System.out.println("The thread will pack");
LockSupport.park();
System.out.println("The thread packed");
});
threadA.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
LockSupport.unpark(threadA);
}

该例会发现,在调用完park后就立即返回了,是因为在使用unpark时已经给过该线程许可了,而park恢复调度的条件就是有一个可用的许可证所以会立即返回

park

除了无参的park以外还有几个有参的重载函数

1
2
3
4
5
public static void park(Object blocker);
public static void parkNanos(Object blocker, long nanos);
public static void parkUntil(Object blocker, long deadline);
public static void parkNanos(long nanos);
public static void parkUntil(long deadline);

park(Object blocker)

使用该方法会将blocker赋值给线程对象中的parkBlocker实例对象中,用于增加阻塞标识,看几个案例很直白的可以理解清楚。

1
LockSupport.pack()

使用该方法阻塞线程,然后我输入jstack查看线程情况

1
2
3
"main" #1 prio=5 os_prio=31 cpu=289.76ms elapsed=13.36s tid=0x00007ff598000000 nid=0x1a03 waiting on condition  [0x000070000129b000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.1/Native Method)

当我使用blocker

1
2
3
4
5
6
class Task extends Thread{
@Override
public void run() {
LockSupport.park(this);
}
}

使用jstack查看线程情况

1
2
3
4
5
"Thread-0" #12 prio=5 os_prio=31 cpu=0.32ms elapsed=49.76s tid=0x00007f8f658e7000 nid=0xa103 waiting on condition  [0x0000700002463000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.1/Native Method)
- parking to wait for <0x0000000787ed1ac8> (a org.yuequan.recast.thread.basic.Task)
at java.util.concurrent.locks.LockSupport.park(java.base@11.0.1/LockSupport.java:194)

你会发现日志上回多一行parking to wait for…

接着介绍其它的API

parkNanos(Object blocker, long nanos)

阻塞对象加nanos,是指在阻塞到设定的纳秒时间后自动返回(如果期间内没有被unpark)

parkUntil(Object blocker, long deadline)

后面的单位是一个时间戳,要从1970到要阻塞的时间一起来计算来时阻塞到设定的时间后自动返回(如果期间没有被unpark)

parkNanos(long nanos)

阻塞到设定的纳秒时间后自动返回(如果期间内没有被unpark)

parkUntil(long deadline)

从1970到要阻塞的时间一起来计算来时阻塞到设定的时间后自动返回(如果期间没有被unpark)

注意事项

在使用park时如果发生中断,park也会直接返回但是不会抛出中断异常InterruptedException,所以在判断阻塞条件的时候,请把该事项考虑进去,是否需要照顾到中断。

原文作者:yuequan

原文链接:http://www.lunaspring.com/2018/11/04/juc_lock_support/

发表日期:November 4th 2018, 7:02:00 pm

更新日期:June 20th 2019, 4:08:11 pm

版权声明:© 月泉 - 邓亮泉 版权所有

CATALOG
  1. 1. LockSupport是什么
  2. 2. LockSupport怎么用
    1. 2.1. park
    2. 2.2. 注意事项