LockSupport的简单使用

141 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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.lambdatestLS2testLS22(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.lambdatestLS2testLS22(T05LockSupport.java:44)
... 1 more
main结束

先调用unpark后调用park

如果先调用了unpark方法,那么线程再调用park方法时不会再被阻塞,而是直接放行。

这样写不会出错,不过平日里没有这么使用的。都是先阻塞,后唤醒

总结

LockSupport的作用就是阻塞/唤醒线程。且被中断时不会抛出异常