zoukankan      html  css  js  c++  java
  • JUC之LockSupport构建同步组件的基本工具

    一、前言

      LockSupport工具类用于阻塞或唤醒线程。LockSupport定义了一组的公共静态方法,这些方法提供了最基本的线程组阻塞和唤醒功能,而LockSupport也成为构建同步组件的基础工具。

      LockSupport定义了一组以park开头的方法用来阻塞当前线程,以及unpark(Thread thread)方法来唤醒一个被阻塞的线程。

    二、源码分析

    2.1 属性

    public class LockSupport {
        // 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实例
                UNSAFE = sun.misc.Unsafe.getUnsafe();
                // 线程类类型
                Class<?> tk = Thread.class;
                // 获取Thread的parkBlocker字段的内存偏移地址
                parkBlockerOffset = UNSAFE.objectFieldOffset
                    (tk.getDeclaredField("parkBlocker"));
                // 获取Thread的threadLocalRandomSeed字段的内存偏移地址
                SEED = UNSAFE.objectFieldOffset
                    (tk.getDeclaredField("threadLocalRandomSeed"));
                // 获取Thread的threadLocalRandomProbe字段的内存偏移地址
                PROBE = UNSAFE.objectFieldOffset
                    (tk.getDeclaredField("threadLocalRandomProbe"));
                // 获取Thread的threadLocalRandomSecondarySeed字段的内存偏移地址
                SECONDARY = UNSAFE.objectFieldOffset
                    (tk.getDeclaredField("threadLocalRandomSecondarySeed"));
            } catch (Exception ex) { throw new Error(ex); }
        }
    }

    2.2 构造器

     // 私有构造函数,无法被实例化

    private LockSupport() {}

    2.3 方法

      LockSupport方法都是基于Unsafe类中定义的park和unpark方法

    ① park方法

      阻塞当前线程,如果调用unpark(Thread thread) 方法或者当前线程被中断,才能从park() 方法返回

    //获取许可,设置时间无限长,直到可以获取许可
    public static void park() {
         UNSAFE.park(false, 0L);//调用本地方法park
    }
    public static void park(Object blocker) { Thread t = Thread.currentThread(); //当前线程 setBlocker(t, blocker); //设置Blocker UNSAFE.park(false, 0L); //调用本地方法park setBlocker(t, null); //重新可运行后再次设置Blocker }

    ② parkNanos方法

      阻塞当前线程,最长不超过nanos纳秒,返回条件在park() 的基础上增加了超时返回

    public static void parkNanos(long nanos) {
            if (nanos > 0)  //时间要大于0
                UNSAFE.park(false, nanos); //给定时间阻塞
        }
    public static void parkNanos(Object blocker, long nanos) {
            if (nanos > 0) { //时间大于0 
                Thread t = Thread.currentThread(); //当前线程
                setBlocker(t, blocker); //设置Blocker
                UNSAFE.park(false, nanos); //设置指定时间阻塞
                setBlocker(t, null); //设置Blocker
            }
        }

    ③ parkUntil方法

      阻塞当前线程,知道deadline时间(从1970年开始到deadline时间的毫秒数)

    public static void parkUntil(long deadline) {
            UNSAFE.park(true, deadline);
        }
    public static void parkUntil(Object blocker, long deadline) {
            Thread t = Thread.currentThread();
            setBlocker(t, blocker);
            UNSAFE.park(true, deadline);
            setBlocker(t, null);
        }

    上面其中三个方法中,都连续调用链setBlocker() ,为什么呢?

    1. 调用park函数时,当前线程首先设置好parkBlocker字段,然后再调用Unsafe的park函数,此后,当前线程就已经阻塞了;

    2. 等待该线程的unpark函数被调用,所以后面的一个setBlocker函数无法运行,unpark函数被调用,该线程获得许可后,就可以继续运行了;

    3. 也就运行第二个setBlocker,把该线程的parkBlocker字段设置为null,这样就完成了整个park函数的逻辑。

    如果没有第二个setBlocker,那么之后没有调用park(Object blocker),而直接调用getBlocker函数,得到的还是前一个park(Object blocker)设置的blocker,显然是不符合逻辑的。总之,必须要保证在park(Object blocker)整个函数执行完后,该线程的parkBlocker字段又恢复为null。

    ④ unpark方法

      唤醒处于阻塞状态的线程thread

    public static void unpark(Thread thread) {
        if (thread != null) // 线程为不空
            UNSAFE.unpark(thread); // 释放该线程许可
    }

    ⑤ setBlocker() 和 getBlocker()

    // 设置当前线程阻塞的原因,可以方便调试(线程在哪个对象上阻塞了)
    private
    static void setBlocker(Thread t, Object arg) { // Even though volatile, hotspot doesn't need a write barrier here. UNSAFE.putObject(t, parkBlockerOffset, arg); } public static Object getBlocker(Thread t) { if (t == null) throw new NullPointerException(); return UNSAFE.getObjectVolatile(t, parkBlockerOffset); }

    感谢:https://www.cnblogs.com/leesf456/p/5347293.html

  • 相关阅读:
    【HDOJ】2774 Shuffle
    【POJ】2170 Lattice Animals
    【POJ】1084 Square Destroyer
    【POJ】3523 The Morning after Halloween
    【POJ】3134 Power Calculus
    【Latex】如何在Latex中插入伪代码 —— clrscode3e
    【HDOJ】4801 Pocket Cube 的几种解法和优化
    【HDOJ】4080 Stammering Aliens
    【HDOJ】1800 Flying to the Mars
    SQL语法
  • 原文地址:https://www.cnblogs.com/FondWang/p/12112251.html
Copyright © 2011-2022 走看看