LockSupport是JUC锁中比较基础的类,用来创建锁和其他同步类的基本线程阻塞原语。比如,在AQS中就使用LockSupport作为基本线程阻塞原语。它的park()和unpark()方法分别用于阻塞线程和解除阻塞线程。与Thread.suspend()相比,它没有由于resume()在前发生,导致线程无法继续执行的问题。和Object.wait()对比,它不需要先获得某个对象的锁,能够响应中断请求(中断状态被设置成true),也不会抛出InterruptException异常。
函数列表
//方法摘要
static Object getBlocker(Thread t)
//返回提供给最近一次尚未解除阻塞的 park 方法调用的 blocker 对象,如果该调用不受阻塞,则返回 null。
static void park()
//为了线程调度,禁用当前线程,除非许可可用。
static void park(Object blocker)
//为了线程调度,在许可可用之前禁用当前线程。
static void parkNanos(long nanos)
//为了线程调度禁用当前线程,最多等待指定的等待时间,除非许可可用。
static void parkNanos(Object blocker, long nanos)
//为了线程调度,在许可可用前禁用当前线程,并最多等待指定的等待时间。
static void parkUntil(long deadline)
//为了线程调度,在指定的时限前禁用当前线程,除非许可可用。
static void parkUntil(Object blocker, long deadline)
//为了线程调度,在指定的时限前禁用当前线程,除非许可可用。
static void unpark(Thread thread)
//如果给定线程的许可尚不可用,则使其可用。
许可
此类以及每个使用它的线程与一个许可关联。如果许可可用,当前线程可获取许可执行。如果许可不可用,调用park()后,当前线程阻塞,等待获取许可。unpark(Thread thread)可使指定线程的许可可用。这与Semaphore相似,但LockSupport最多只能有一个许可。
运行如下代码:
public static void main(String[] args) {
LockSupport.park();
System.out.println("helloworld");
}
会发现线程一直处于阻塞状态,helloworld一直打印不出啦。说明LockSupport.park();执行时,许可是不可用的。这说明许可默认是不可用的。
再执行如下代码;
public static void main(String[] args) {
Thread thread = Thread.currentThread();
LockSupport.unpark(thread);
LockSupport.park();
System.out.println("helloworld");
}
会发现helloworld打印出来了。这印证了上面的结论。
blocker
三种形式的park(park(Object blocker)、parkNanos(Object blocker, long nanos)、parkUntil(Object blocker, long deadline))都支持blocker对象参数。此对象在线程受阻塞时被记录,以允许监视工具和诊断工具确定线程受阻塞的原因。监视工具和诊断工具可以使用方法getBlocker(java.lang.Thread)访问 blocker。建议最好使用这些形式,而不是不带此参数的原始形式。在锁实现中提供的作为blocker的普通参数是this。
响应中断
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "阻塞了");
LockSupport.park();
if (Thread.interrupted()) {
System.out.println(Thread.currentThread().getName() + "中断了");
}
System.out.println(Thread.currentThread().getName() + "运行了");
}
});
t.start();
t.interrupt();
}
运行结果:
Thread-0阻塞了
Thread-0中断了
Thread-0运行了
说明线程如果因为调用park而阻塞的话,能够响应中断请求(中断状态被设置成true),不会抛出InterruptedException。
如果将LockSupport.park();
替换为wait(),且给run()加锁,
Thread t = new Thread(new Runnable() {
@Override
public synchronized void run() {
System.out.println(Thread.currentThread().getName() + "阻塞了");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (Thread.interrupted()) {
System.out.println(Thread.currentThread().getName() + "中断了");
}
System.out.println(Thread.currentThread().getName() + "运行了");
}
});
t.start();
t.interrupt();
运行结果:
Thread-0阻塞了
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Unknown Source)
at com.thread.locksupport.ParkTest3$1.run(ParkTest.java:32)
at java.lang.Thread.run(Unknown Source)
Thread-0运行了
说明,和Object.wait()对比,LockSupport不需要先获得某个对象的锁,能够响应中断请求(中断状态被设置成true),也不会抛出InterruptException异常。
源码
待补充
本文就讲到这里,想了解Java并发编程更多内容请参考:
- Java并发编程札记-目录