LockSupport线程工具类解析

在以往的线程交互中,我们唤醒线程或者阻塞线程一般都是用notify/wait/await等等函数,但是还是不够灵活。例如说,我现在有十个线程,如果是我想唤醒或者挂起这其中的一部分线程的话,那我可以使用Condition,将这部分线程分队列,也就是ReentrantLock里面的,newCondition,但是此时我的需求是想要唤醒第七个线程,然后让第二个线程阻塞,那么不管是Condition还是wait,notify,都显得麻烦,力不从心,因此为了解决这个问题,就出现了这个线程工具类Locksupport

LockSupport概述

LockSupport是为了方便的对线程进行交互,而开发出来的线程工具类。基于UnSafe来实现的,最主要的作用是挂起和唤醒线程。

对于LockSupport来说,用的最多的以及最重要的方法,就是Park()系列方法和UnPark()系列方法了。

park方法

pack

方法 解释
park(Object) 挂起当前线程
parkNanos(Object,long) 指定了一个挂起时间(相对于当前的时间),时间到后自动被唤醒;例如1000纳秒后自动唤醒
parkUntil(Object,long) 指定一个挂起时间(绝对时间),时间到后自动被唤醒;例如2018-02-1221点整自动被唤醒。
park() 和park(Object)相比少了挂起前为线程设置blocker、被唤醒后清理blocker的操作。
parkNanos(long) 和parkNanos(Object,long)类似,仅少了blocker相关的操作
parkUntil(long) 和parkUntil(Object,long)类似,仅少了blocker相关的操作
  • park(Object) 源码
public static void park(Object blocker) {
            //获取当前线程
            Thread t = Thread.currentThread();
            //设置线程parkBlocker
            setBlocker(t, blocker);
            //阻塞线程
            UNSAFE.park(false, 0L);
            //清除parkBlocker
            setBlocker(t, null);
        }

可以看到,park是默认阻塞的是当前的线程。举个代码的例子

public class LockSupportDemo1 {
    public static void main(String[] args) {
        System.out.println("开始");
        LockSupport.park();
        System.out.println("结束");
    }
}

这个程序只会输出开始,而且一直都不会结束,因为主线程已经被阻塞了。但是没有其他的线程唤醒它,就会被一直阻塞住。在别的线程调用UnPark方法的时候,并且把当前线程作为参数时,那个因为调用了park方法而被阻塞的线程才会被唤醒

unPark方法

    public static void unpark(Thread thread) {
        if (thread != null)
            UNSAFE.unpark(thread);
    

这个方法其实很简单,传入需要唤醒的线程的引用,然后就会唤醒那个线程。另外还有一个特点就是,当线程在调用park()之前调用了unPark,那么park方法也会被马上唤醒。像这样

public class LockSupportDemo1 {
    public static void main(String[] args) {
        System.out.println("开始");
        LockSupport.unpark(Thread.currentThread());
        LockSupport.park();
        System.out.println("结束");
    }
}

像这样,代码的输出仍然会是

开始
结束

应用代码示例

要求:两个线程交替输出1A2B......,思路,这个时候就可以用到LockSupport,当输出完一次之后,就休眠当前线程,唤醒另一个线程去输出

/**
 * 两个线程交替输出1A2B......
 */
public class Test2 {
static  Thread t1 = null;
   static Thread t2 = null;
    public static void main(String[] args) {


        char[] num = "123456789".toCharArray();
        char[] words = "ABCDEFGHI".toCharArray();


        t1 = new Thread(() ->{
           for (int i=0;i<num.length;i++){
               System.out.println(num[i]);
               LockSupport.park();
               LockSupport.unpark(t2);
           }
        },"t1");

        t2 = new Thread(() ->{
            for (int i=0;i<words.length;i++){
                System.out.println(words[i]);
                LockSupport.unpark(t1);
                LockSupport.park();
            }
        },"t2");
        t1.start();
        t2.start();

    }
}

posted @ 2020-05-25 20:35  穿黑风衣的牛奶  阅读(367)  评论(1编辑  收藏  举报