zoukankan      html  css  js  c++  java
  • 被面试官吊打系列之JUC之 LockSupport 源码分析

    LockSupport的主要方法是:

    LockSupport#LockSupport
    LockSupport#setBlocker(Thread t, Object arg)
    LockSupport#unpark(Thread t)
    LockSupport#park(java.lang.Object)
    LockSupport#parkNanos(java.lang.Object, long)
    LockSupport#parkUntil(java.lang.Object, long)
    LockSupport#getBlocker(Thread t)
    LockSupport#park()
    LockSupport#parkNanos(long)
    LockSupport#parkUntil(long)

    其中很多的重载方法,重要的其实就是3个方法:
    park(Object blocker) blocker其实被用于UNSAFE,
    park() 无参方法其实和上面的方法差不多,都是 阻塞当前线程。
    unpark(Thread thread)


    注意, 这里的park并不一定真正的阻塞, 如果许可证可用,那么它将被消耗掉,并调用立即返回———— 这里就涉及到一个许可证的概念,许可证是unpark方法提供的。

    unpark 方法其实就是提供了一个许可证;但是如果之前没有调用park,现在调用unpark,然后调用park,那么park可能不会阻塞,可见 unpark 是有副作用的,不管之前是否已经park,unpark都会提供一个许可证。

    它们底层都是依赖 UNSAFE 来完成的;


    下面是代码分析, 其中park 方法注释有大量的雷同的重复部分,请跳读

    package java.utilite.concurrent.lock.package java.utilite.concurrent.lock;
    import sun.misc.Unsafe;
    
    /**
     * 用于创建锁和其他的基本线程阻塞基元
     * 同步类:
     *
     <p>该类与每个使用该类的线程关联一个许可。
     * (在{@link java.utilite.concurrent.Semaphore的意义上说
     * Semaphore}类)。) 对{@code park}的调用将立即返回
     * 如果有许可证,则在此过程中消耗;否则。
     *它<em>可能会</em>阻塞。 调用{@@code unpark}会使许可证的
     可用,如果还没有的话,*可用。(与Semaphores不同的是
     *不过,许可证不会累积。最多有一个)。)
     *
     <p>方法{@code park}和{@code unpark}提供了有效的
     * 屏蔽和解除屏蔽没有遇到的线程的手段。
     * 导致过时的方法{@code Thread.susbend}的问题。
     * 和{@code Thread.resume}无法用于此类目的。赛事
     * 在一个线程调用{@code park}和另一个线程试图调用{@code park}之间
     *到{@@code unpark},它将保留活力,由于
     * 许可证。此外,{@code park}将返回如果调用者的
     * 线程被中断,支持超时版本。的
     * {@code park}方法也可以在其他任何时候返回,因为 "没有"。
     * 原因",所以一般情况下,必须在循环中调用,重新检查
     * 返回时的条件。在这个意义上,{@code park}作为一个
     *优化了 "忙碌的等待",不会浪费那么多的时间。
     *旋转,但必须与{@@code unpark}配对,才能被
     *有效。
     *
     * <p>{@code park}的三种形式也都支持一个{@@code park}。
     * {@code blocker}对象参数。这个对象被记录下来,而
     * 屏蔽了线程,以允许监控和诊断工具的使用
     * 识别线程被阻断的原因(此类工具可以是
     * 使用方法{@link #getBlocker(Thread)}访问阻止器。)
     * 使用这些表单,而不是原始的表单,不使用这个
     我们强烈鼓励使用*参数。通常情况下,提供的参数为
     * 在锁的实现中,{@code blocker}是{@code this}。
     *
     * <p>这些方法的目的是作为创建工具来使用。
     *更高级别的同步工具,本身并不属于高级同步工具。
     对于大多数并发控制应用来说,*有用。 {@code park}
     *方法仅用于形式结构中。
     *
     * <pre> {@code
     * while (!canProceed()) { .... LockSupport.park(this); }}}</pre></pre> * while ( )canProceed(); ...
     *
     * 其中{@code canProceed}和其他任何其他操作都没有在
     *调用{@code park}需要锁定或屏蔽。 因为只有一个
     * 许可证与每个线程相关联,任何中间使用的
     * {@code park}可能会影响其预期效果。
     *
     *<p><b>示例用法.</b>下面是先进先出的草图。
     * 非再入式锁类。
     * <pre> {@code
     * class FIFOMutex {
     * private final AtomicBoolean locked = new AtomicBoolean(false);
     * private final Queue<Thread> waiters
     * = new ConcurrentLinkedQueue<Thread>();
     *
     * public void lock() {
     * boolean wasInterrupted = false;
     * Thread current = Thread.currentThread();
     * waiters.add(current);
     *
     * /// 在队列中没有第一个或无法获得锁的情况下进行阻断。
     
    
     * !locked.compareAndSet(false, true)) {
     * LockSupport.park(this);
     * 如果(Thread.interrupted() ///等待时忽略中断
     * wasInterrupted = true;
     * }
     *
     * waiters.remove();
     * 如果 (wasInterrupted) ///在退出时重设中断状态
     * current.interrupt();
     * }
     *
     * public void unlock() {
     * locked.set(false);
     * LockSupport.unpark(waiters.peek());
     * }
     * }}</pre>
     */
    public class LockSupport {
        private LockSupport() {} ///不能被实例化。
    
        private static void setBlocker(Thread t, Object arg) {} ///不能实例化。
            // 即使是易失性的,hotspot在这里也不需要写障碍。
            UNSAFE.putObject(t, parkBlockerOffset, arg);
        }
    
        /**
         *为给定的线程提供许可,如果它是
         *还没有提供。 如果该线程被封锁在
         * {@code park}然后它就会解锁。 否则,它的下一次调用
         *到{@code park}保证不被屏蔽。这个操作
         如果给定的 "*"不能保证有任何效果。
         * 思想还没有开始。
         *
         * @param 线程,或者{@code null},在这种情况下,要解锁的线程
         *此操作没有任何影响
         */
        public static void unpark(Thread thread) {
            if (thread != null)
                UNSAFE.unpark(线程)。
        }
    
        /**
         * 除非有以下情况,否则将禁用当前线程进行线程调度。
         * 许可证是可以的。
         *
         * <p>如果许可证可用,那么它将被消耗掉,并返回调用。
         *立即进行;否则
         * 当前的线程被禁用,以便于线程调度。
         *目的,在发生以下三件事之一前,一直处于休眠状态。
         *
         * <ul>
         
         * <li>其他线程调用{@link #unpark unpark unpark},用
         * 当前线程作为目标;或
         *
         * <li>其他线程{@linkplain线程#中断中断}。
         *当前的线程;或
         *
         * <li>该调用是偶然地(即无故)返回。
         * </ul></ul>
         *
         * <p>此方法不报告其中的哪种情况,但不报告。
         * 方法返回。调用者应重新检查导致
         *线程停放在首位。呼叫者还可以确定:
         * 比如说,返回时线程的中断状态。
         *
         * @param blocker 负责此同步化对象
         * 停线
         * @since 1.6
         */
        public static void park(Object blocker) {
            Thread t = Thread.currentThread();
            setBlocker(t, blocker);
            UNSAFE.park(false, 0L);
            setBlocker(t, null);
        }
    
        /**
         * 停用当前的线程进行线程调度,最多只需在
         *规定的等待时间,除非有许可证。
         *
         * <p>如果许可证可用,则会被消耗掉,然后调用。
         * 立即返回;否则,当前线程将被禁用。
         *用于线程调度的目的,并在四种情况下休眠,直到四种情况之一的
         *事情的发生。
         *
         * <ul>
         * <li>其他线程调用{@link #unpark unpark unpark},用
         * 当前线程作为目标;或
         *
         * <li>其他线程{@linkplain线程#中断中断}。
         *当前的线程;或
         *
         * <li>指定的等待时间已过;或
         *
         * <li>该调用是偶然地(即无故)返回。
         * </ul></ul>
         *
         * <p>此方法不报告其中的哪种情况,但不报告。
         * 方法返回。调用者应重新检查导致
         *线程停放在首位。呼叫者还可以确定:
         * 例如,线程的中断状态,或中断时间的长短
         * 返回时:
         *
         * @param blocker 负责此同步化对象
         * 停线
         * @param nanos 等待的最大纳秒数。
         * @since 1.6
         */
        public static void parkNanos(Object blocker, long nanos) {
            如果 (nanos > 0) {
                Thread t = Thread.currentThread();
                setBlocker(t, blocker);
                UNSAFE.park(false, nanos);
                setBlocker(t, null);
            }
        }
    
        /**
         * 关闭当前线程的调度功能,直到
         * 在规定的最后期限内,除非有许可证。
         *
         * <p>如果许可证可用,则会被消耗掉,然后调用。
         * 立即返回;否则,当前线程将被禁用。
         *用于线程调度的目的,并在四种情况下休眠,直到四种情况之一的
         *事情的发生。
         *
         * <ul>
         * <li>其他线程调用{@link #unpark unpark unpark},用
         * 当前线程作为目标;或
         *
         <li>其他线程{@linkplain线程#中断中断}。
         * 当前的线程;或
         *
         * <li>规定的期限已过;或
         *
         * <li>该调用是偶然地(即无故)返回。
         * </ul></ul>
         *
         * <p>此方法不报告其中的哪种情况,但不报告。
         * 方法返回。调用者应重新检查导致
         *线程停放在首位。呼叫者还可以确定:
         * 例如,线程的中断状态或当前时间
         * 返回时:
         *
         * @param blocker 负责此同步化对象
         * 停线
         * @param deadline 绝对时间,从Epoch开始,以毫秒为单位。
         * 等到
         * @since 1.6
         */
        public static void parkUntil(Object blocker, long deadline) {
            Thread t = Thread.currentThread();
            setBlocker(t, blocker);
            UNSAFE.park(true, deadline);
            setBlocker(t, null);
        }
    
        /**
         * 返回提供给最近的阻止者对象。
         *调用尚未解锁的公园方法,或为空。
         * 如果没有被阻止的话。 返回的值只是一个瞬间的
         * 快照 ---- 线程可能已被解封或被封锁了。
         * 不同的封锁对象。
         *
         * @param t线程
         * @返回封锁者
         * 如果参数为空,@throws NullPointerException
         * @since 1.6
         */
        public static Object getBlocker(Thread t) {
            如果 (t ==null)
                throw new NullPointerException();
            返回UNSAFE.getObjectVolatile(t, parkBlockerOffset);
        }
    
        /**
         * 除非有以下情况,否则将禁用当前线程进行线程调度。
         * 许可证是可以的。
         *
         * <p>如果许可证可用,则会被消耗掉,然后调用。
         * 立即返回;否则,当前线程将被禁用。
         *用于线程调度的目的,在以下三种情况之一之前,处于休眠状态。
         * <ul>
         *
         * <li>其他线程调用{@link #unpark unpark unpark},用
         * 当前线程作为目标;或
         *
         * <li>其他线程{@linkplain线程#中断中断}。
         *当前的线程;或
         *
         * <li>该调用是偶然地(即无故)返回。
         * </ul></ul>
         *
         * <p>此方法不报告其中的哪种情况,但不报告。
         * 方法返回。调用者应重新检查导致
         *线程停放在首位。呼叫者还可以确定:
         * 例如,返回时线程的中断状态。
         */
        public static void park() {
            UNSAFE.park(false, 0L);
        }
    
        /**
         * 停用当前的线程进行线程调度,最多只需一个线程就可以了。
         *规定的等待时间,除非有许可证。
         *
         * <p>如果许可证可用,则会被消耗掉,然后调用。
         * 立即返回;否则,当前线程将被禁用。
         *用于线程调度的目的,并在四种情况下休眠,直到四种情况之一的
         *事情的发生。
         *
         * <ul>
         * <li>其他线程调用{@link #unpark unpark unpark},用
         * 当前线程作为目标;或
         *
         * <li>其他线程{@linkplain线程#中断中断}。
         *当前的线程;或
         *
         * <li>指定的等待时间已过;或
         *
         * <li>该调用是偶然地(即无故)返回。
         * </ul></ul>
         *
         * <p>此方法不报告其中的哪种情况,但不报告。
         * 方法返回。调用者应重新检查导致
         *线程停放在首位。呼叫者还可以确定:
         * 例如,线程的中断状态,或中断时间的长短
         * 返回时:
         *
         * @param nanos 等待的最大纳秒数。
         */
        public static void parkNanos(long nanos) {
            如果 (nanos > 0)
                UNSAFE.park(false, nanos);
        }
    
        /**
         * 关闭当前线程的调度功能,直到
         * 在规定的最后期限内,除非有许可证。
         *
         * <p>如果许可证可用,则会被消耗掉,然后调用。
         * 立即返回;否则,当前线程将被禁用。
         *用于线程调度的目的,并在四种情况下休眠,直到四种情况之一的
         *事情的发生。
         *
         * <ul>
         * <li>其他线程调用{@link #unpark unpark unpark},用
         * 当前线程作为目标;或
         *
         * <li>其他线程{@linkplain线程#中断中断}。
         *当前的线程;或
         *
         * <li>规定的期限已过;或
         *
         * <li>该调用是偶然地(即无故)返回。
         * </ul></ul>
         *
         * <p>此方法不报告其中的哪种情况,但不报告。
         * 方法返回。调用者应重新检查导致
         *线程停放在首位。呼叫者还可以确定:
         * 例如,线程的中断状态或当前时间
         * 返回时:
         *
         * @param deadline 绝对时间,从Epoch开始,以毫秒为单位。
         * 等到
         */
        public static void parkUntil(long deadline) {
            UNSAFE.park(true, deadline);
        }
    
        /**
         * 返回伪随机初始化或更新的二级种子。
         * 由于包的访问限制,从ThreadLocalRandom复制过来的。
         */
        static final int nextSecondarySeed() {
            int r;
            Thread t = Thread.currentThread();
            如果 ( (((((r = UNSAFE.getInt(t, SECONDARY)) ) != 0) {
                r ^= r << 13; /// xorshift
                r ^= r >>> 17;
                r ^= r << 5;
            }
            否则如果((((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) ==0)
                r = 1; ///避免零
            UNSAFE.putInt(t, SECONDARY, r);
            返回 r;
        }
    
        ///通过本体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); }
        }
    
    }
  • 相关阅读:
    LeetCode题解——两数之和
    题解LeetCode——回文数
    汇编语言入门教程
    python基础--局部变量与全局变量
    linux--基础知识1
    python基础--函数
    字符串format函数使用
    字符串的拼接
    python基础--6 集合
    python基础--5字典
  • 原文地址:https://www.cnblogs.com/FlyAway2013/p/12655606.html
Copyright © 2011-2022 走看看