并发包中的LockSupport工具类

一、 LockSupport简介

LockSupport类是一个Java6(JSR166-JUC)引入的一个工具类,它的主要作用是对线程进行挂起和唤醒,它是创建锁和其他同步类的基础。

LockSupport类的核心方法其实就两个:park()和unpark(),其中park()方法用来阻塞当前调用线程,unpark()方法用于唤醒指定线程。这和Object的wait/notify、Condition的await/signal、以及Semaphore的acquire/release功能类似。
但是LockSupport的这两种方法从语意上讲比Object类的方法更清晰,而且可以针对指定线程进行阻塞和唤醒
注意:park方法真正的实现是Unsafe类

private static final sun.misc.Unsafe UNSAFE;
public static void park() {
        UNSAFE.park(false, 0L);
}

LockSupport类使用了一种名为Permit(许可)的概念来做到阻塞和唤醒线程的功能,可以把许可看成是一种(0,1)信号量(Semaphore),但与 Semaphore 不同的是,许可的累加上限是1。
初始时,permit为0,当调用unpark()方法时,线程的permit加1,当调用park()方法时,如果permit为0,则调用线程进入阻塞状态。

二、 LockSupport API

Park方法:

如果调用LockSupport.park()方法的线程已经拿到了与LockSupport关联的许可证,则调用时会马上返回,否则调用线程会被禁止参与线程的调度,也就是会被阻塞挂起。

public class LockSupportMain {
    public static void main(String[] args) {
        System.out.println("main线程----------park前");
   //直接在main函数中调用park()方法,当前线程被挂起。
        //在默认情况下,调用线程是不持有许可证的。
        LockSupport.park();
        System.out.println("main线程----------park后");
    }
}
****************************只会输出调用park()方法前内容*******
main线程----------park前

unPark(Thread thread):

当一个线程调用LockSupport.unpark()方法时,如果参数thread线程没有持有thread与LockSupport类关联的许可证,则让thread线程持有;

而如果thread之前因调用LockSupport.park()方法时被挂起,则调用LockSupport.unpark()方法后,该线程会被唤醒。

而如果thread之前没有调用LockSupport.park()方法,则调用LockSupport.unpark()方法后,再调用LockSupport.park()方法,其会立刻返回。

public class LockSupportMain {
    public static void main(String[] args) {
        System.out.println("main线程----------park前");
        //使用当前线程获取到许可证
        LockSupport.unpark(Thread.currentThread());
        LockSupport.park();
        System.out.println("main线程----------park后");
    }
}
*******************************************
main线程----------park前
main线程----------park后
public class LockSupportMain {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("子线程开始...");
            //调用LockSupport.park()方法,挂起自己
            //默认情况下,子线程没有持有许可证,因而它会把自己挂起。
            LockSupport.park();
            System.out.println("调用park后,改行不会打印,直到LockSupport.unpark(thread)唤醒后,
才会打印这行,子线程才会结束.");

        });
        thread.start();

        try {
            Thread.sleep(10_000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //10s后,main线程调用LockSupport.unpark()方法让thread线程持有许可证,
        //然后LockSupport.park()方法返回。
        LockSupport.unpark(thread);
    }
}

LockSupport的使用过程中还需要注意以下几点:

  • 和wait方法一样,park方法也需要在循环体中使用。这是为了防止线程被唤醒后,不进行判断而意外继续向下执行。
  • park方法是会响应中断的,但是不会抛出异常。(也就是说如果当前调用线程被中断,则会立即返回但不会抛出中断异常)
  • park的重载方法park(Object blocker),会传入一个blocker对象,所谓Blocker对象,其实就是当前线程调用时所在调用对象(如上述示例中的FIFOMutex对象)。该对象一般供监视、诊断工具确定线程受阻塞的原因时使用。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容