⭕ LockSupport

吞佛童子2022年10月10日
  • Java
  • Concurrenty
大约 3 分钟

⭕ LockSupport

1. 类描述

  1. 方法 parkunpark 提供了 阻塞 & 解除阻塞线程 的有效方法,
    • 这些线程不会遇到导致不推荐使用的方法 Thread.suspend 和 Thread.resume 无法用于此类目的的问题:
      • 一个调用 park 的线程和另一个试图解除它的线程之间的竞争由于许可,将保持活力。
  2. 此外,如果调用者的线程被中断,park 将返回,
  3. 支持超时版本。
  4. park 方法也可以在任何其他时间“无缘无故”地返回,
  5. 因此通常必须在循环中调用,该循环在返回时重新检查条件。
    • 从这个意义上说,park 是“忙等待”的优化,不会浪费太多时间,但必须与 unpark() 对才能有效。
  6. 基于 UNSAFE 类 实现

使用

  • 实现 先进先出不可重入锁类:
 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);

     // 队头线程非当前线程 || CAS 修改原子类 locked 为 true 失败
     while (waiters.peek() != current || !locked.compareAndSet(false, true)) {
       LockSupport.park(this); // 阻塞当前线程
       if (Thread.interrupted()) // 清空中断标志位,忽略中断
         wasInterrupted = true;
     }

     waiters.remove();
     if (wasInterrupted)          // reassert interrupt status on exit
       current.interrupt();
   }

   // 释放锁
   public void unlock() {
     locked.set(false);
     LockSupport.unpark(waiters.peek()); // 唤醒队头线程
   }
 }

2. 类图

public class LockSupport {
    private LockSupport() {} // 私有构造函数,无法实例化
    // ...
}

3. 常用方法

    // 如果许可可用,则使用它并立即返回调用;否则,当前线程出于线程调度目的而被禁用并处于休眠状态,直到发生以下三种情况之一: 
    // 1. 其他一些线程以当前线程为目标调用 unpark;
    // 2. 其他一些线程中断当前线程;
    // 3. 虚假(即无缘无故)的调用返回。
    public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        UNSAFE.park(false, 0L);
        setBlocker(t, null);
    }
    public static void park() {
        UNSAFE.park(false, 0L);
    }
    
    // 如果许可可用,则使用它并立即返回调用;否则,当前线程出于线程调度目的而被禁用并处于休眠状态,直到发生以下四种情况之一: 
    // 1. 其他一些线程以当前线程为目标调用 unpark;
    // 2. 其他一些线程中断当前线程;
    // 3. 指定的等待时间过去;
    // 4. 虚假(即无缘无故)的调用返回。
    public static void parkNanos(long nanos) {
        if (nanos > 0)
            UNSAFE.park(false, nanos);
    }
    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);
        }
    }
    
    // 如果许可可用,则使用它并立即返回调用;否则,当前线程出于线程调度目的而被禁用并处于休眠状态,直到发生以下四种情况之一: 
    // 1. 其他一些线程以当前线程为目标调用 unpark;
    // 2. 其他一些线程中断当前线程;
    // 3. 指定的截止日期已过;
    // 4. 虚假(即无缘无故)的调用返回。
    public static void parkUntil(Object blocker, long deadline) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        UNSAFE.park(true, deadline);
        setBlocker(t, null);
    }
    public static void parkUntil(long deadline) {
        UNSAFE.park(true, deadline);
    }
    
    private static void setBlocker(Thread t, Object arg) {
        // Even though volatile, hotspot doesn't need a write barrier here.
        UNSAFE.putObject(t, parkBlockerOffset, arg);
    }
    
    // 如果线程在 park 上被阻塞,那么它将解除阻塞。如果给定线程尚未启动,则不保证此操作有任何效果。
    public static void unpark(Thread thread) {
        if (thread != null)
            UNSAFE.unpark(thread);
    }
    
    // ------------ UNSAFE 类 ----------------
    // 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); }
    }
上次编辑于: 2022/10/10 下午8:43:48
贡献者: liuxianzhishou