java多线程 LockSupport源码分析

目录

简介

构造函数,方法setBlocker,unpark,park,parkNanos,parkUtil

方法getBlocker,park,parkNanos,parkUtil,nextSecondarySeed

字段UNSAFE,parkBlockerOffset,SEED,PROBE,SECONDARY


简介

package java.util.concurrent.locks;
import sun.misc.Unsafe;

/**
 * 用于创建锁和其他同步类的基本线程阻塞原语。
 *
 * <p>这个类与每个使用它的线程关联一个许可(某种意义上类似Semaphore)。
 * 如果许可证可用,对park的调用将立即返回,并在此过程中消耗许可证;
 * 否则可能阻塞。
 * 调用unpark使许可证可用(如果它已经不可用的话)。
 * (与Semaphores不同的是,许可证不会累积。最多只有一个。)
 *
 * <p>方法park和unpark提供了阻塞和解除阻塞线程的有效方法,不会遇到导致已弃用方法Thread.suspend和resume的问题,这些可能会不安全。
 * 在一个调用park的线程和另一个试图unpark它的线程之间的竞争将会保留活的状态,由于许可证的原因。
 * 此外,如果调用者的线程被中断,那么park将返回,并且支持超时版本。
 * park方法也可以在任何其他时间返回,因为“没有原因”,所以通常必须在返回时重新检查条件的循环中调用。
 * 从这个意义上说,park可以作为“忙碌等待”的优化,不会浪费太多的时间,但必须与unpark配合才能有效。
 *
 * <p>这三种形式的park都支持一个blocker对象参数。
 * 当线程被阻塞时,该对象被记录,以允许监视和诊断工具识别线程阻塞的原因。
 * (这类工具可以使用getBlocker(Thread)方法访问拦截器。)
 * 强烈建议使用这些形式,而不是不带此参数的原始形式。
 * 在锁实现中提供正常参数是this。
 *
 * <p>这些方法被设计为用于创建高级同步实用程序的工具,它们本身对大多数并发控制应用程序并不有用。
 * park方法仅用于下列形式的结构中:
 *
 *  <pre> {@code
 * while (!canProceed()) { ... LockSupport.park(this); }}</pre>
 *
 * 在这种情况下,canProceed和调用park之前的任何其他操作都不需要锁定或阻塞。
 * 因为每个线程只关联一个许可证,所以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);
 *
 *     // 阻塞而不是在队列的第一个或不能获得锁
 *     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());
 *   }
 * }}</pre>
 */
public class LockSupport 

java多线程 LockSupport源码分析

构造函数,方法setBlocker,unpark,park,parkNanos,parkUtil

    private LockSupport() {} // 不能实例化

    private static void setBlocker(Thread t, Object arg) {
        // 即使是volatile, hotspot在这里也不需要写屏障。
    	// 线程t对应arg
        UNSAFE.putObject(t, parkBlockerOffset, arg);
    }

    /**
     * 为给定的线程提供许可(如果它还不可用的话)。
     * 如果线程在park时被阻塞,那么它将被解除阻塞。
     * 否则,它的下一个对park的调用保证不会阻塞。
     * 如果给定的线程没有启动,这个操作不能保证有任何效果。
     *
     * @param thread the thread to unpark, or {@code null}, in which case
     *        this operation has no effect
     */
    public static void unpark(Thread thread) {
        if (thread != null)
            UNSAFE.unpark(thread);
    }

    /**
     * 为线程调度目的禁用当前线程,除非许可可用。
     *
     * <p>如果许可证是可用的,那么它将被消耗,调用将立即返回;
     * 否则,当前线程在线程调度中会被禁用,并处于休眠状态,直到以下三种情况之一发生:
     *
     * <ul>
     * <li>其他一些线程以当前线程为目标调用unpark;或
     *
     * <li>其他线程中断当前线程;或
     *
     * <li>调用会假地(也就是说,无缘无故地)返回。
     * </ul>
     *
     * <p>此方法不报告是哪一个导致方法返回。
     * 调用者应该重新检查导致线程停在第一个位置的条件。
     * 调用者也可以确定,例如,线程返回时的中断状态。
     *
     * @param blocker the synchronization object responsible for this
     *        thread parking
     * @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>其他一些线程以当前线程为目标调用unpark;或
     *
     * <li>其他线程中断当前线程;或
     *
     * <li>指定的等待时间已经过去;或
     *
     * <li>调用会假地(也就是说,无缘无故地)返回。
     * </ul>
     *
     * <p>此方法不报告是哪一个导致方法返回。
     * 调用者应该重新检查导致线程停在第一个位置的条件。
     * 调用者也可以确定,例如,线程的中断状态,或者返回时经过的时间。
     *
     * @param blocker the synchronization object responsible for this
     *        thread parking
     * @param nanos the maximum number of nanoseconds to wait
     * @since 1.6
     */
    public static void parkNanos(Object blocker, long nanos) {
        if (nanos > 0) {
            Thread t = Thread.currentThread();
            setBlocker(t, blocker);
            UNSAFE.park(false, nanos);
            setBlocker(t, null);
        }
    }

    /**
     * 为线程调度目的禁用当前线程,直到指定的截止日期,除非许可可用。
     *
     * <p>如果许可证是可用的,那么它将被消耗,调用将立即返回;
     * 否则,当前线程会因为线程调度的目的而被禁用,并处于休眠状态,直到以下四种情况之一发生:
     *
     * <ul>
     * <li>其他一些线程以当前线程为目标调用unpark;或
     *
     * <li>其他线程中断当前线程;或
     *
     * <li>指定期限已过;或
     *
     * <li>调用会假地(也就是说,无缘无故地)返回。
     * </ul>
     *
     * <p>此方法不报告是哪一个导致方法返回。
     * 调用者应该重新检查导致线程停在第一个位置的条件。
     * 调用者也可以确定,例如,线程的中断状态,或当前时间。
     *
     * @param blocker the synchronization object responsible for this
     *        thread parking
     * @param deadline the absolute time, in milliseconds from the Epoch,
     *        to wait until
     * @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);
    }


方法getBlocker,park,parkNanos,parkUtil,nextSecondarySeed


    /**
     * 返回提供给最近调用的尚未解除阻塞的park方法的阻塞器对象,或者null如果未被阻塞。
     * 返回的值只是一个瞬时快照——线程可能已经在不同的blocker对象上解除了阻塞或阻塞。
     *
     * @param t the thread
     * @return the blocker
     * @throws NullPointerException if argument is null
     * @since 1.6
     */
    public static Object getBlocker(Thread t) {
        if (t == null)
            throw new NullPointerException();
        return UNSAFE.getObjectVolatile(t, parkBlockerOffset);
    }

    /**
     * Disables the current thread for thread scheduling purposes unless the
     * permit is available.
     *
     * <p>If the permit is available then it is consumed and the call
     * returns immediately; otherwise the current thread becomes disabled
     * for thread scheduling purposes and lies dormant until one of three
     * things happens:
     *
     * <ul>
     *
     * <li>Some other thread invokes {@link #unpark unpark} with the
     * current thread as the target; or
     *
     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
     * the current thread; or
     *
     * <li>The call spuriously (that is, for no reason) returns.
     * </ul>
     *
     * <p>This method does <em>not</em> report which of these caused the
     * method to return. Callers should re-check the conditions which caused
     * the thread to park in the first place. Callers may also determine,
     * for example, the interrupt status of the thread upon return.
     */
    public static void park() {
    	// 这种与上面的区别是,不再setBlocker
        UNSAFE.park(false, 0L);
    }

    /**
     * Disables the current thread for thread scheduling purposes, for up to
     * the specified waiting time, unless the permit is available.
     *
     * <p>If the permit is available then it is consumed and the call
     * returns immediately; otherwise the current thread becomes disabled
     * for thread scheduling purposes and lies dormant until one of four
     * things happens:
     *
     * <ul>
     * <li>Some other thread invokes {@link #unpark unpark} with the
     * current thread as the target; or
     *
     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
     * the current thread; or
     *
     * <li>The specified waiting time elapses; or
     *
     * <li>The call spuriously (that is, for no reason) returns.
     * </ul>
     *
     * <p>This method does <em>not</em> report which of these caused the
     * method to return. Callers should re-check the conditions which caused
     * the thread to park in the first place. Callers may also determine,
     * for example, the interrupt status of the thread, or the elapsed time
     * upon return.
     *
     * @param nanos the maximum number of nanoseconds to wait
     */
    public static void parkNanos(long nanos) {
        if (nanos > 0)
            UNSAFE.park(false, nanos);
    }

    /**
     * Disables the current thread for thread scheduling purposes, until
     * the specified deadline, unless the permit is available.
     *
     * <p>If the permit is available then it is consumed and the call
     * returns immediately; otherwise the current thread becomes disabled
     * for thread scheduling purposes and lies dormant until one of four
     * things happens:
     *
     * <ul>
     * <li>Some other thread invokes {@link #unpark unpark} with the
     * current thread as the target; or
     *
     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
     * the current thread; or
     *
     * <li>The specified deadline passes; or
     *
     * <li>The call spuriously (that is, for no reason) returns.
     * </ul>
     *
     * <p>This method does <em>not</em> report which of these caused the
     * method to return. Callers should re-check the conditions which caused
     * the thread to park in the first place. Callers may also determine,
     * for example, the interrupt status of the thread, or the current time
     * upon return.
     *
     * @param deadline the absolute time, in milliseconds from the Epoch,
     *        to wait until
     */
    public static void parkUntil(long deadline) {
        UNSAFE.park(true, deadline);
    }

    /**
     * 返回伪随机初始化或更新的次级种子。
     * 由于包访问限制,从ThreadLocalRandom复制。
     */
    static final int nextSecondarySeed() {
        int r;
        Thread t = Thread.currentThread();
        if ((r = UNSAFE.getInt(t, SECONDARY)) != 0) {
            r ^= r << 13;   // xorshift
            r ^= r >>> 17;
            r ^= r << 5;
        }
        else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0)
            r = 1; // avoid zero
        UNSAFE.putInt(t, SECONDARY, r);
        return r;
    }


字段UNSAFE,parkBlockerOffset,SEED,PROBE,SECONDARY

    // 通过intrinsic API实现Hotspot
    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); }
    }

 

上一篇:java多线程并发之原子操作-CAS以及原子类atomic


下一篇:Unsafe源码与翻译