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
构造函数,方法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,Thread,thread,UNSAFE,park,源码,线程,unpark,多线程 来源: https://blog.csdn.net/xushiyu1996818/article/details/112863318