LockSupport 工具类
LockSupport 是 rt.jar 包中的一个工具类,它的次要作用就是 挂起
和唤醒
线程,并且 该类是创立锁和其它同步类的根底。
LockSupport 类和每个应用它的线程都会关联一个 许可证
,在默认状况下调用 LockSupport 类的办法是不持有许可证的。LockSupport 是应用 Unsafe 类实现的。
上面介绍一下 LockSupport 中的次要办法。
void park()
如果在调用 park()办法之前曾经取得到关联的许可证,则调用后会立刻返回,否则会被禁止参加线程的调度,也就是被阻塞挂起。
如下代码,最终只会输入“开始”,而后以后线程被挂起,因为在默认状况下调用线程是不持有许可证的。
public static void main(String[] args) throws Exception {System.out.println("开始...");
LockSupport.park();
System.out.println("完结...");
}
// 后果:// 开始...
在其它线程调用 unpark(Thread thread)办法并且将以后阻塞线程作为参数时,调用 park()办法阻塞的线程会被返回。当其它线程调用了阻塞线程的 interrupt()办法,设置中断标记或者线程被虚伪唤醒,则阻塞线程也会被返回。
须要留神:
- 当调用 park()办法被阻塞的线程被其它线程中断而返回时候,并不会抛出 InterruptedException 异样。
- 许可证是一次性的。比方线程 B 间断调用了三次 unpark()办法,当线程 A 调用 park()办法就应用掉这个许可证,如果线程 A 再次调用 park()办法,则进入期待状态。
void unpark(Thread t)
当一个线程调用 unpark()办法时,如果传入的参数 thread 没有持有许可证,则让传入的 thread 持有许可证;如果 thread 之前调用 park()后被挂起,则调用 unpark()时会唤醒该 thread;如果 thread 之前没有调用 park(),则调用 unpark()办法后,再调用 park()办法时会立刻返回。
public static void main(String[] args) throws Exception {System.out.println("开始...");
LockSupport.unpark(Thread.currentThread());
LockSupport.park();
System.out.println("完结...");
}
// 输入后果:// 开始...
// 完结...
看如下代码,加深对 park 和 unpark 的了解。
public static void main(String[] args) throws Exception {Thread t = new Thread(() -> {System.out.println("子线程开始...");
// 挂起本人
LockSupport.park();
System.out.println("子线程完结...");
});
t.start();
Thread.sleep(1000);
System.out.println("主线程开始调用 unpark");
LockSupport.unpark(t);
}
// 输入后果:// 子线程开始...
// 主线程开始调用 unpark
// 子线程完结...
该段代码首先创立了子线程 t,子线程启动后调用 park()办法。因为默认状况下子线程没有持有许可证,则挂起本人。
主线程休眠 1 秒后,调用 unpark()并传入子线程 t,这样做就是为了让子线程获取到许可证,之后子线程中阻塞的 park()就会返回。
void parkNanos(long nanos)
和 park()办法相似,如果曾经获取到了许可证则调用该办法后会马上返回。不同的是,如果没有拿到许可证,则调用线程会被挂起 nanos 工夫后主动返回。
另外 park()办法还反对带有 blocker 参数的办法 void park(Object blocker)办法,当线程在没有持有许可证的状况下调用 park()办法而被阻塞挂起时,这个 blocker 对象会被记录到该线程外部。个别用于用于标识阻塞对象,该对象次要用于问题排查和系统监控。
void parkNanos(Object blocker,long nanos) 该办法绝对于上个办法,减少了超时工夫。
void parkUntil(Object blocker,long deadline)
public static void parkUntil(Object blocker, long deadline) {Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(true, deadline);
setBlocker(t, null);
}
参数 deadline 的工夫单位为 ms,这个办法和 parkNanos(Object blocker,long nanos)的区别是,后者是从以后工夫期待 nanos 秒工夫,而前者是指定一个工夫点,比方 2022-01-19 12:00:00。
总结
与 Object 类的 wait/notify 机制相比,park/unpark 有两个长处:
- 以 thread 为操作对象更合乎阻塞线程的直观定义
- 操作更精准,能够精确地唤醒某一个线程(notify 随机唤醒一个线程,notifyAll 唤醒所有期待的线程),减少了灵活性