开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 13 天,点击查看活动详情
使用
LockSupport底层采用UnSafe类实现硬件级别的操作。它类似于一种许可证。
- 当调用park方法时就会检查线程是否有许可证(最开始,每个线程都是没有关联许可证的),若没有则阻塞线程。
- 当调用unpark方法时,(unpark的参数就是线程)会给指定线程一个许可证,此时线程拿到许可证之后,就可以从调用park处返回了。
下面是一个示例
@Test
public void testLS() throws Exception{
Thread t1 = new Thread(()->{
System.out.println("线程1");
LockSupport.park();
System.out.println("线程1结束");
});
t1.start();
Thread.sleep(3000);
LockSupport.unpark(t1);
Thread.sleep(1000);
System.out.println("main结束");
}
输出结果如下
线程1
线程1结束
main结束
JUC中许多源码都涉及到了LockSupport,都是使用LockSupport来进行阻塞线程的,有点类似于wait/notify这对儿组合方法。
调用park方法的线程被中断了怎么办?
了解了LockSupport怎么使用之后,会不会觉得它和wait/notify方法太像了?我们思考下,假设线程t1调用了park方法处于阻塞状态,当t1还在阻塞状态时,并且没有其他的线程来调用unpark方法唤醒他,那么中断该线程会发生什么?先来说答案:当调用了t1的interrupt方法中断线程后,t1会从调用park处直接返回,直接解除阻塞状态,继续执行后续的代码,并且不会报错。
下面是代码示例
@Test
public void testLS1() throws Exception{
Thread t1 = new Thread(()->{
System.out.println("线程1");
LockSupport.park();
System.out.println("线程1结束");
});
t1.start();
Thread.sleep(3000);
t1.interrupt();
Thread.sleep(1000);
System.out.println("main结束");
}
输出结果如下和第一小节一模一样
线程1
线程1结束
main结束
和wait方法的对比
如果场景一模一样,使用wait方法让线程进入阻塞,然后再中断线程会发生什么呢?先来说答案:会从调用wait方法处抛出异常,需要调用者自行处理。抛出异常后如果不处理,则可以继续执行后续代码,如果throw new了,则直接返回。
@Test
public void testLS2() throws Exception {
Object obj = new Object();
Thread t1 = new Thread(() -> {
synchronized (obj) {
System.out.println("线程1");
try {
obj.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e); // 此处抛出了异常,故不能继续执行后续代码
}
System.out.println("线程1结束");
}
});
t1.start();
Thread.sleep(3000);
t1.interrupt();
Thread.sleep(1000);
System.out.println("main结束");
}
输出结果如下
线程1
Exception in thread "Thread-0" java.lang.RuntimeException: java.lang.InterruptedException at juc.T05LockSupport.lambda2(T05LockSupport.java:46)
at java.lang.Thread.run(Thread.java:750)
Caused by: java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at juc.T05LockSupport.lambda2(T05LockSupport.java:44)
... 1 more
main结束
先调用unpark后调用park
如果先调用了unpark方法,那么线程再调用park方法时不会再被阻塞,而是直接放行。
这样写不会出错,不过平日里没有这么使用的。都是先阻塞,后唤醒
总结
LockSupport的作用就是阻塞/唤醒线程。且被中断时不会抛出异常