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