zoukankan      html  css  js  c++  java
  • 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());
        }
    }

    参考自《java并发编程之美》

  • 相关阅读:
    漫画图解红黑树
    HashMap原理
    从底层原理深度剖析volatile关键字
    一致性哈希算法
    OAuth2.0 授权模式详解
    RocketMQ消息的顺序、重复和事务
    正向代理 vs 反向代理
    JVM内存分配以及存储
    023_JDK8.0新特性<四>StreamAPI_4_Stream终止操作
    022_JDK8.0新特性<四>StreamAPI_3_Stream中间操作
  • 原文地址:https://www.cnblogs.com/wqff-biubiu/p/12169110.html
Copyright © 2011-2022 走看看