Análisis de código fuente de LockSupport multiproceso de Java

Tabla de contenido

Introducción

Constructor, conjunto de métodosBlocker, unpark, park, parkNanos, parkUtil

方法 getBlocker, park, parkNanos, parkUtil, nextSecondarySeed

字段 INSEGURO, parkBlockerOffset, SEED, PROBE, SECONDARY


Introducción

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 

Constructor, conjunto de métodosBlocker, 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;
    }


字段 INSEGURO, 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); }
    }

 

Supongo que te gusta

Origin blog.csdn.net/xushiyu1996818/article/details/112863318
Recomendado
Clasificación