LockSupport类

Posted wqff-biubiu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LockSupport类相关的知识,希望对你有一定的参考价值。

LockSupport类是个工具类,主要作用是挂起和唤醒线程,是创建锁与其他同步类的基础

LockSupport类与每个使用它的线程都会关联一个许可证,默认情况下调用LockSupport类的方法的线程是不持有许可证的。LockSupport是unsafe类park、unpark方法的封装使用。

一、构造方法与变量

    private LockSupport() {} // Cannot be instantiated.工具类不能实例化

    // Hotspot implementation via intrinsics API
    private static final sun.misc.Unsafe UNSAFE;
    private static final long parkBlockerOffset;
    private static final long SEED;
    private static final long PROBE;
    private static final long SECONDARY;
    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> tk = Thread.class;
            parkBlockerOffset = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("parkBlocker"));
            SEED = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomSeed"));
            PROBE = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomProbe"));
            SECONDARY = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomSecondarySeed"));
        } catch (Exception ex) { throw new Error(ex); }
    }

二、方法

LockSupport的方法基本上是unsafe的简单封装,如下park(Object blocker)的源码。

blocker是阻塞时记录到线程内部的对象,在线程阻塞时,诊断工具可以获取对象进行分析,JDK推荐使用带参数blocker的park方法,将blocker设置为this,可打印线程堆栈排查问题时得知哪个类被阻塞了

    public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);//
        UNSAFE.park(false, 0L);
        setBlocker(t, null);//
    }

三、例子及部分方法的说明

public class LockSupportTest {

    /**
     * LockSupport.park():阻塞线程
     * 当前线程已拿到LockSupport关联的许可证时,立刻返回
     * 否则阻塞挂起
     */
    @Test
    public void parkTest(){
        System.out.println("begin park!");
        LockSupport.park();
        System.out.println("end park");
    }

    /**
     * LockSupport.unpark():线程唤醒
     * 参数线程如果没有持有thread与LockSupport的关联许可证,则让线程持有,
     * park()后unpark(thread)可以唤醒park()阻塞的thread--下面unparkTest2()
     * 若unpark后park(),--下面unparkTest()
     */
    @Test
    public void unparkTest(){
        System.out.println("begin park!");
        LockSupport.unpark(Thread.currentThread());
        LockSupport.park();
        System.out.println("end park");
    }

    @Test
    public void unparkTest2() throws InterruptedException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("child thread begin park");
                LockSupport.park();
                System.out.println("child thread unpark");
            }
        });
        thread.start();
        Thread.sleep(1000);
        System.out.println("main thread begin unpark");
        LockSupport.unpark(thread);
    }

    /**
     * thread.interrupt()也可以引起park()的返回
     * 所以park()阻塞后返回,不会告诉是何种原因返回,所以需要根据park()原因,检查条件是否满足
     * 即是否符合条件后unpark还是被中断
     * @throws InterruptedException
     */
    @Test
    public void unparkTest3() throws InterruptedException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("child thread begin park!");
                while(!Thread.currentThread().isInterrupted()){
                    LockSupport.park();
                }
                System.out.println("child thread unpark");
            }
        });
        thread.start();
        Thread.sleep(1000);
        System.out.println("main thread begin unpark");
        thread.interrupt();
    }

    public void testPark(){
        LockSupport.park(this);
    }

    /**
     * park(Object blocker),阻塞时,传入this,可检查哪个类阻塞
     * 当线程唤醒后,会清除blocker,所以一般都是在线程阻塞时才分析原因blocker
     */
    @Test
    public void parkTest1(){
        LockSupportTest test = new LockSupportTest();
        test.testPark();
    }

    /**
     * parkNanos(long nanos),阻塞nanos纳秒
     */
    @Test
    public void parkNanosTest(){
        System.out.println("begin park!");
        LockSupport.parkNanos(2000000000);//ns
        System.out.println("end park");
    }

    /**
     * parkUntil(long nanos),阻塞至deadline毫秒
     */
    @Test
    public void parkUntilTest(){
        System.out.println("begin park!");
        LockSupport.parkUntil(this, new Date().getTime() + 10000);//ms
        System.out.println("end park");
    }

}

FIFO锁

public class FIFOMutex {

    private final AtomicBoolean locked = new AtomicBoolean(false);
    private final Queue<Thread> waiters = new ConcurrentLinkedDeque<>();

    public void lock(){
        boolean wasInterrupted = false;
        Thread current = Thread.currentThread();
        waiters.add(current);

        while (waiters.peek() != current || !locked.compareAndSet(false,true)){//不是队首元素或者锁已被其他线程获取
            LockSupport.park(this);
            if (Thread.interrupted()){//如果是中断引起的返回,擦除中断标记,重新循环
                wasInterrupted = true;
            }
        }
        waiters.remove();
        if (wasInterrupted){//恢复中断标记
            current.interrupt();
        }
    }

    public void unlock(){
        locked.set(false);
        LockSupport.unpark(waiters.peek());
    }
}

以上是关于LockSupport类的主要内容,如果未能解决你的问题,请参考以下文章

LockSupport类

LockSupport 线程工具类有啥用?

3.1.7 线程阻塞工具类:LockSupport

线程阻塞工具类:LockSupport(读书笔记)

Java并发:挂起与唤醒线程LockSupport工具类详解

Java多线程——线程阻塞工具类LockSupport