本文是学习LockSupport期间记录的,一篇文章发太多内容,编辑的时候很卡,所以独立开一篇
LockSupport篇:https://blog.csdn.net/hhy107107/article/details/108041627
说明:在阅读LockSupport源码的时候顺便翻译的,大部分用的google翻译,不太通顺的改成了自己的理解。一般还过得去的(基本能看懂的),就没改。
/** Written by Doug Lea with assistance from members of JCP JSR-166* Expert Group and released to the public domain, as explained at* http://creativecommons.org/publicdomain/zero/1.0/*/package java.util.concurrent.locks;
import sun.misc.Unsafe;/*** 用于创建锁和其他同步类的线程阻塞基本原语。** 此类与使用它的每个线程关联一个许可(在{@link java.util.concurrent.Semaphore Semaphore}类的意义上)。* 如果有许可证,将立即返回对{@code park}的调用,并在此过程中消耗掉它; 否则可能会阻塞。 调用{@code unpark}可使许可证可用(如果尚不可用)。* (不过与信号量不同,许可证不会累积。最多只能有一个。)** 方法{@code park}和{@code unpark}提供了有效的阻塞和解阻塞线程的方法,* 这些线程不会遇到{@code Thread.suspend}和{@code Thread.resume}所可能引发的死锁问题* 由于许可的存在,在调用{@code park}的一个线程与试图进行{@code unpark}的另一个线程之间进行的竞争将保持活性。* 此外,如果调用者的线程被中断并且支持超时版本,则{@code park}将返回。* {@code park}方法也可能在其他任何时间出于“无理由”返回,因此通常必须在循环中调用该循环,该循环在返回时会重新检查条件。* 从这个意义上说,{@code park}是对“忙等待”的优化,它不会浪费太多的时间,而必须与{@code unpark}配对才能生效。** {@code park}的三种形式也都支持{@code blocker}对象参数。 线程被阻塞时会记录该对象,以允许监视和诊断工具确定线程被阻塞的原因。* (此类工具可以使用方法{@link #getBlocker(Thread)}访问阻止程序。)强烈建议使用这些形式,而不使用没有此参数的原始形式。* 在锁实现中作为{@code blocker}提供的正常参数是{@code this}。** 这些方法旨在用作创建更高级别的同步实用程序的工具,而对于大多数并发控制应用程序本身并不有用。 {@code park}方法仅设计用于以下形式的构造:** <pre> {@code* while (!canProceed()) { ... LockSupport.park(this); }}</pre>** {@code canProceed}或调用{@code park}之前的任何其他操作均不需要锁定。 因为每个线程仅关联一个许可,所以{@code 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);** // Block while not first in queue or cannot acquire lock* while (waiters.peek() != current ||* !locked.compareAndSet(false, true)) {* LockSupport.park(this);* if (Thread.interrupted()) // ignore interrupts while waiting* wasInterrupted = true;* }** waiters.remove();* if (wasInterrupted) // reassert interrupt status on exit* current.interrupt();* }** public void unlock() {* locked.set(false);* LockSupport.unpark(waiters.peek());* }* }}</pre>*/
public class LockSupport {private LockSupport() {} // Cannot be instantiated.// 设置线程t的parkBlocker字段的值为argprivate static void setBlocker(Thread t, Object arg) {// Even though volatile, hotspot doesn't need a write barrier here.UNSAFE.putObject(t, parkBlockerOffset, arg);}/*** 如果尚未提供给定线程的许可,则使其可用。* 如果线程被park{@code park},调用unpark唤醒线程。 unpark将确保线程的下一次{@code park}可用。* 如果给定线程尚未启动,则不能保证此操作完全无效。** @param thread 要唤醒的线程,如果为null,此操作无效*/public static void unpark(Thread thread) {if (thread != null)UNSAFE.unpark(thread);}/*** 除非有许可,否则出于线程调度目的禁用当前线程。** 如果许可证可用,则将其消耗掉,并立即返回;* 否则,出于线程调度的目的,当前线程将被禁用,并处于休眠状态,直到发生以下三种情况之一:** <ul>* <li>1. 其他一些线程以当前线程为目标来调用{@link #unpark unpark};** <li>2. 其他一些线程中断当前线程 {@linkplain Thread#interrupt interrupts};** <li>3. 虚假的调用返回 (没有原因); 笔者:这说的啥,我也没看懂* </ul>** <p>此方法不报告上述那种情况导致方法返回。* 调用者应重新检查导致线程首先停滞的条件。 调用者还可以确定例如返回时线程的中断状态。** @param blocker 使线程阻塞的这个对象* @since 1.6*/public static void park(Object blocker) {Thread t = Thread.currentThread();setBlocker(t, blocker);UNSAFE.park(false, 0L);setBlocker(t, null);}/*** 除非有许可,否则出于线程调度目的禁用当前线程一定时间。** 如果许可证可用,则将其消耗掉,并立即返回;* 否则,出于线程调度的目的,当前线程将被禁用,并处于休眠状态,直到发生以下四种情况之一:** <ul>* <li>1. 其他一些线程以当前线程为目标来调用{@link #unpark unpark};** <li>2. 其他一些线程中断当前线程 {@linkplain Thread#interrupt interrupts};** <li>3. 指定的时间已经过去** <li>4. 虚假的调用返回 (没有原因); 笔者:这说的啥,我也没看懂* </ul>** <p>此方法不报告上述那种情况导致方法返回。* 调用者应重新检查导致线程首先停滞的条件。 调用者还可以确定例如返回时线程的中断状态或返回时所经过的时间。** @param blocker 使线程阻塞的这个对象* @param nanos 最大等待纳秒数* @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);}}/*** 除非指定许可,否则出于线程调度目的禁用当前线程,直到指定的期限。** 如果许可证可用,则将其消耗掉,并立即返回;* 否则,出于线程调度的目的,当前线程将被禁用,并处于休眠状态,直到发生以下四种情况之一:** <ul>* <li>1. 其他一些线程以当前线程为目标来调用{@link #unpark unpark};** <li>2. 其他一些线程中断当前线程 {@linkplain Thread#interrupt interrupts};** <li>3. 指定的时间已经过去** <li>4. 虚假的调用返回 (没有原因); 笔者:这说的啥,我也没看懂* </ul>** <p>此方法不报告上述那种情况导致方法返回。* 调用者应重新检查导致线程首先停滞的条件。 调用者还可以确定例如返回时线程的中断状态或返回时所经过的时间。** @param blocker 使线程阻塞的这个对象* @param deadline 距纪元的绝对时间(时间戳)(以毫秒为单位)* @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);}/*** 返回造成线程park的对象* 未park,返回null* 返回的值只是一个瞬时快照-此线程可能已解除阻塞或在其他阻塞对象上被阻塞。** @param t 线程* @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);}/*** 同{@link #park(Object blocker)},只不过少了blocker而已*/public static void park() {UNSAFE.park(false, 0L);}/*** 同{@link #parkNanos(Object blocker, long nanos)},只不过少了blocker而已*/public static void parkNanos(long nanos) {if (nanos > 0)UNSAFE.park(false, nanos);}/*** 同{@link #parkUntil(Object blocker, long deadline)},只不过少了blocker而已*/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; // xorshiftr ^= r >>> 17;r ^= r << 5;}else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0)r = 1; // avoid zeroUNSAFE.putInt(t, SECONDARY, r);return r;}// Hotspot implementation via intrinsics APIprivate static final sun.misc.Unsafe UNSAFE;// 表示内存偏移地址: parkBlocker用于记录线程被谁阻塞的,用于线程监控和分析工具来定位原因。parkBlocker是Thread的属性。private static final long parkBlockerOffset;private static final long SEED;private static final long PROBE;// 表示内存偏移地址private static final long SECONDARY;static {try {// 获取Unsafe实例UNSAFE = sun.misc.Unsafe.getUnsafe();// 线程类类型Class<?> tk = Thread.class;// 获取Thread的parkBlocker字段的内存偏移地址parkBlockerOffset = UNSAFE.objectFieldOffset(tk.getDeclaredField("parkBlocker"));// 获取Thread的threadLocalRandomSeed字段的内存偏移地址SEED = UNSAFE.objectFieldOffset(tk.getDeclaredField("threadLocalRandomSeed"));// 获取Thread的threadLocalRandomProbe字段的内存偏移地址PROBE = UNSAFE.objectFieldOffset(tk.getDeclaredField("threadLocalRandomProbe"));// 获取Thread的threadLocalRandomSecondarySeed字段的内存偏移地址SECONDARY = UNSAFE.objectFieldOffset(tk.getDeclaredField("threadLocalRandomSecondarySeed"));} catch (Exception ex) { throw new Error(ex); }}}