一个很灵活的线程工具类LockSupport

LockSupport是一个编程工具类,主要是为了阻塞和唤醒线程用的。使用它我们可以实现很多功能。

LockSupport简介

LockSupport是什么

LockSupport是一个线程工具类,所有的方法都是静态方法,可以让线程在任意位置阻塞,也可以在任意位置唤醒

它的内部其实两类主要的方法:park(停车阻塞线程)和unpark(启动唤醒线程)。

注意上面的123方法,都有一个blocker,这个blocker是用来记录线程被阻塞是被谁阻塞的。用于线程监控和分析工具来定位原因的。

现在我们知道了LockSupport是用来阻塞和唤醒线程的,而且之前相信我们都知道wait/notify也是用来阻塞和唤醒线程的,那么它相比,LockSupport有什么优点呢?

与wait/notify对比

我们先来举一个使用案例:

public class LockSupportTest {

    static class MyThread extends Thread{
        @Override
        public void run() {
            System.out.println("进入线程");
            LockSupport.park();
            System.out.println("t1线程运行结束");
        }
    }

    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.start();
        System.out.println("t1线程启动了,但是内部进行了park");
        LockSupport.unpark(t1);
        System.out.println("LockSupport进行了unpark");
    }
}

上面这段代码的意思是,我们定义一个线程,但是在内部进行了park,因此需要unpark才能唤醒继续执行,不过上面,我们在MyThread进行的park,在main线程进行的unpark。

这样来看,好像和wait/notify没有什么区别。那它们的区别到底是什么呢?这个就需要仔细的观察了。这里主要有两点:

(1)wait和notify都是Object中的方法,在调用这两个方法前必须先获得锁对象,但是park不需要获取某个对象的锁就可以锁住线程

(2)notify只能随机选择一个线程唤醒,无法唤醒指定的线程,但是unpark可以唤醒一个指定的线程

前面我们介绍了线程一共有六种状态,而park系列方法线程进入两种状态:WAITING等待状态或TIMED_WAITING等待状态。这两种状态都会使线程阻塞在当前位置。

那么怎么唤醒这两种状态的线程呢?

对于WAITING等待状态有两种唤醒方式:

  • 调用对应的唤醒方法。这里就是LockSupport的unpark方法。
  • 调用该线程变量的interrupt()方法,会唤醒该线程,并抛出InterruptedException异常。

对于TIMED_WAITING等待状态来说,它比WAITING状态多了一种唤醒方式,就是超过规定时间,那么线程会自动醒来。

LockSupport使用

示例1:在主线程中调用LockSupport.park(currentThread);将组线程阻塞,然后通过子线程完成5秒睡眠换后唤醒主线程。
public class LockSupportDemo {

    public static void main(String[] args) {

        //获取当前线程
        final Thread currentThread = Thread.currentThread();
        
        Runnable runnable = new Runnable() {

            @Override
            public void run() {
                try {
                    //睡眠5秒,等待主线程调用park
                    Thread.sleep(5000);
                    System.out.println("子线程进行unpark操作!");
                    // 进行唤醒给定的currentThread线程
                    LockSupport.unpark(currentThread);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        };

        new Thread(runnable).start();
        System.out.println("开始阻塞!");
        // 进行阻塞给定的currentThread线程
        LockSupport.park(currentThread);
        System.out.println("结束阻塞!");

    }

}
示例2:
public class LockSupportDemo {

    public static void main(String[] args) {

        //获取当前线程
        final Thread currentThread = Thread.currentThread();
     
        //在park之前先进行一次unpark
        LockSupport.unpark(currentThread);
         
        
        System.out.println("开始阻塞!");
        // 由于在park之前进行了一次unpark,所以会抵掉本次的park操作。因而不会阻塞在此处
        LockSupport.park(currentThread);
        System.out.println("结束阻塞!");

    }

}

 

posted @ 2022-02-08 13:19  残城碎梦  阅读(58)  评论(0编辑  收藏  举报