目录
简介
java.util.concurrent.locks.LockSupport 是一个工具类,提供了基本的线程阻塞和唤醒功能,它是创建锁和其他同步组件的基础工具,内部是基于 sun.misc.Unsafe
类实现的。
LockSupport 和使用它的线程都会关联一个许可:
-
park 方法表示消耗一个许可,调用 park 方法时,如果许可可用,则 park 方法返回,如果没有许可,则一直阻塞直到许可可用;
-
unpark 方法表示增加一个许可,多次调用并不会积累许可,因为许可数最大值为 1。
方法介绍
-
park()
: 阻塞当前线程,直到unpark方法被调用或当前线程被中断,park方法才会返回。 -
park(Object blocker)
: 同park()方法,多了一个阻塞对象blocker参数。 -
parkNanos(long nanos)
: 同park方法,nanos表示最长阻塞超时时间,超时后park方法将自动返回。 -
parkNanos(Object blocker, long nanos)
: 同parkNanos(long nanos)方法,多了一个阻塞对象blocker参数。 -
parkUntil(long deadline)
: 同park()方法,deadline参数表示最长阻塞到某一个时间点,当到达这个时间点,park方法将自动返回。(该时间为从1970年到现在某一个时间点的毫秒数) -
parkUntil(Object blocker, long deadline)
: 同parkUntil(long deadline)方法,多了一个阻塞对象blocker参数。 -
unpark(Thread thread)
: 唤醒处于阻塞状态的线程thread。
阻塞和唤醒示例
示例1
子线程执行 LockSupport.park()
,由于没有许可,进入阻塞状态。主线程 3 秒后调用 unpark 方法给子线程增加了一个许可,park 方法返回,子线程被唤醒继续执行。
【示例】:
public class Demo {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
System.out.println("do something start");
LockSupport.park();
System.out.println("do something end");
});
thread.start();
Thread.sleep(3000);
System.out.println("给子线程thread增加一个许可");
LockSupport.unpark(thread);
}
}
输出结果:
do something start
给子线程thread增加一个许可
do something end
示例2
先 unpark 增加许可,随后 park 消费许可也是可以的。unpark 会给 thread 增加一个许可,此时调用 park 方法,由于许可是可用的,所以,park 方法直接返回了。
【示例】:
public class Demo {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println("do something start");
System.out.println("子线程thread给自己增加一个许可");
LockSupport.unpark(Thread.currentThread());
LockSupport.park();
System.out.println("do something end");
});
thread.start();
}
}
输出结果:
do something start
子线程thread给自己增加一个许可
do something end
示例3
连续调用 unpark 不会累计许可,许可最大值为1,第一次 park 就已经消耗了许可,所以第二次 park 一直阻塞。
public class Demo {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println("do something start");
LockSupport.unpark(Thread.currentThread());
System.out.println("unpark 1");
LockSupport.unpark(Thread.currentThread());
System.out.println("unpark 2");
LockSupport.park();
System.out.println("park 1");
LockSupport.park();
System.out.println("park 2");
System.out.println("do something end");
});
thread.start();
}
}
输出结果:
do something start
unpark 1
unpark 2
park 1
阻塞对象 blocker 的作用
通过前面方法介绍可以看到,park、parkNanos、parkUntil 方法都有对应的带阻塞对象 blocker 参数的重载方法。Thread 类有一个变量为 parkBlocker,对应的就是 LockSupport 的 park 等方法设置进去的阻塞对象。
该参数主要用于问题排查和系统监控,在线程 dump 中会显示该参数的信息,有利于问题定位。
【示例】
分别调用 park() 和 park(Object blocker),然后使用 jstack 查看线程堆栈信息,对比发现后者会多输出一条阻塞对象的信息:
park():
public class Demo {
public static void main(String[] args) {
LockSupport.park();
}
}
park(Object blocker):
public class Demo {
public static void main(String[] args) {
LockSupport.park(new Demo());
}
}
和显式锁、隐式锁等待唤醒的区别
-
park和unpark方法的调用不需要获取锁。
-
先调用unpark方法后调用park方法依然可以唤醒。
-
park方法响应中断,线程被中断后park方法直接返回,但是不会抛InterruptedException异常。
-
unpark方法是直接唤醒指定的线程。
参考:
标签:Java,许可,thread,编程,park,LockSupport,unpark,线程 From: https://www.cnblogs.com/larry1024/p/17769054.html