被面试官吊打系列之JUC之 LockSupport 源码分析
作者:互联网
LockSupport的主要方法是:
LockSupport#LockSupport
LockSupport#setBlocker(Thread t, Object arg)
LockSupport#unpark(Thread t)
LockSupport#park(java.lang.Object)
LockSupport#parkNanos(java.lang.Object, long)
LockSupport#parkUntil(java.lang.Object, long)
LockSupport#getBlocker(Thread t)
LockSupport#park()
LockSupport#parkNanos(long)
LockSupport#parkUntil(long)
其中很多的重载方法,重要的其实就是3个方法:
park(Object blocker) blocker其实被用于UNSAFE,
park() 无参方法其实和上面的方法差不多,都是 阻塞当前线程。
unpark(Thread thread)
注意, 这里的park并不一定真正的阻塞, 如果许可证可用,那么它将被消耗掉,并调用立即返回———— 这里就涉及到一个许可证的概念,许可证是unpark方法提供的。
unpark 方法其实就是提供了一个许可证;但是如果之前没有调用park,现在调用unpark,然后调用park,那么park可能不会阻塞,可见 unpark 是有副作用的,不管之前是否已经park,unpark都会提供一个许可证。
它们底层都是依赖 UNSAFE 来完成的;
下面是代码分析, 其中park 方法注释有大量的雷同的重复部分,请跳读:
package java.utilite.concurrent.lock.package java.utilite.concurrent.lock; import sun.misc.Unsafe; /** * 用于创建锁和其他的基本线程阻塞基元 * 同步类: * <p>该类与每个使用该类的线程关联一个许可。 * (在{@link java.utilite.concurrent.Semaphore的意义上说 * Semaphore}类)。) 对{@code park}的调用将立即返回 * 如果有许可证,则在此过程中消耗;否则。 *它<em>可能会</em>阻塞。 调用{@@code unpark}会使许可证的 可用,如果还没有的话,*可用。(与Semaphores不同的是 *不过,许可证不会累积。最多有一个)。) * <p>方法{@code park}和{@code unpark}提供了有效的 * 屏蔽和解除屏蔽没有遇到的线程的手段。 * 导致过时的方法{@code Thread.susbend}的问题。 * 和{@code Thread.resume}无法用于此类目的。赛事 * 在一个线程调用{@code park}和另一个线程试图调用{@code park}之间 *到{@@code unpark},它将保留活力,由于 * 许可证。此外,{@code park}将返回如果调用者的 * 线程被中断,支持超时版本。的 * {@code park}方法也可以在其他任何时候返回,因为 "没有"。 * 原因",所以一般情况下,必须在循环中调用,重新检查 * 返回时的条件。在这个意义上,{@code park}作为一个 *优化了 "忙碌的等待",不会浪费那么多的时间。 *旋转,但必须与{@@code unpark}配对,才能被 *有效。 * * <p>{@code park}的三种形式也都支持一个{@@code park}。 * {@code blocker}对象参数。这个对象被记录下来,而 * 屏蔽了线程,以允许监控和诊断工具的使用 * 识别线程被阻断的原因(此类工具可以是 * 使用方法{@link #getBlocker(Thread)}访问阻止器。) * 使用这些表单,而不是原始的表单,不使用这个 我们强烈鼓励使用*参数。通常情况下,提供的参数为 * 在锁的实现中,{@code blocker}是{@code this}。 * * <p>这些方法的目的是作为创建工具来使用。 *更高级别的同步工具,本身并不属于高级同步工具。 对于大多数并发控制应用来说,*有用。 {@code park} *方法仅用于形式结构中。 * * <pre> {@code * while (!canProceed()) { .... LockSupport.park(this); }}}</pre></pre> * while ( )canProceed(); ... * * 其中{@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); * * /// 在队列中没有第一个或无法获得锁的情况下进行阻断。 * !locked.compareAndSet(false, true)) { * LockSupport.park(this); * 如果(Thread.interrupted() ///等待时忽略中断 * wasInterrupted = true; * } * * waiters.remove(); * 如果 (wasInterrupted) ///在退出时重设中断状态 * current.interrupt(); * } * * public void unlock() { * locked.set(false); * LockSupport.unpark(waiters.peek()); * } * }}</pre> */ public class LockSupport { private LockSupport() {} ///不能被实例化。 private static void setBlocker(Thread t, Object arg) {} ///不能实例化。 // 即使是易失性的,hotspot在这里也不需要写障碍。 UNSAFE.putObject(t, parkBlockerOffset, arg); } /** *为给定的线程提供许可,如果它是 *还没有提供。 如果该线程被封锁在 * {@code park}然后它就会解锁。 否则,它的下一次调用 *到{@code park}保证不被屏蔽。这个操作 如果给定的 "*"不能保证有任何效果。 * 思想还没有开始。 * * @param 线程,或者{@code null},在这种情况下,要解锁的线程 *此操作没有任何影响 */ public static void unpark(Thread thread) { if (thread != null) UNSAFE.unpark(线程)。 } /** * 除非有以下情况,否则将禁用当前线程进行线程调度。 * 许可证是可以的。 * * <p>如果许可证可用,那么它将被消耗掉,并返回调用。 *立即进行;否则 * 当前的线程被禁用,以便于线程调度。 *目的,在发生以下三件事之一前,一直处于休眠状态。 * * <ul> * <li>其他线程调用{@link #unpark unpark unpark},用 * 当前线程作为目标;或 * * <li>其他线程{@linkplain线程#中断中断}。 *当前的线程;或 * * <li>该调用是偶然地(即无故)返回。 * </ul></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); } /** * 停用当前的线程进行线程调度,最多只需在 *规定的等待时间,除非有许可证。 * * <p>如果许可证可用,则会被消耗掉,然后调用。 * 立即返回;否则,当前线程将被禁用。 *用于线程调度的目的,并在四种情况下休眠,直到四种情况之一的 *事情的发生。 * * <ul> * <li>其他线程调用{@link #unpark unpark unpark},用 * 当前线程作为目标;或 * * <li>其他线程{@linkplain线程#中断中断}。 *当前的线程;或 * * <li>指定的等待时间已过;或 * * <li>该调用是偶然地(即无故)返回。 * </ul></ul> * * <p>此方法不报告其中的哪种情况,但不报告。 * 方法返回。调用者应重新检查导致 *线程停放在首位。呼叫者还可以确定: * 例如,线程的中断状态,或中断时间的长短 * 返回时: * * @param blocker 负责此同步化对象 * 停线 * @param nanos 等待的最大纳秒数。 * @since 1.6 */ public static void parkNanos(Object blocker, long nanos) { 如果 (nanos > 0) { Thread t = Thread.currentThread(); setBlocker(t, blocker); UNSAFE.park(false, nanos); setBlocker(t, null); } } /** * 关闭当前线程的调度功能,直到 * 在规定的最后期限内,除非有许可证。 * * <p>如果许可证可用,则会被消耗掉,然后调用。 * 立即返回;否则,当前线程将被禁用。 *用于线程调度的目的,并在四种情况下休眠,直到四种情况之一的 *事情的发生。 * * <ul> * <li>其他线程调用{@link #unpark unpark unpark},用 * 当前线程作为目标;或 * <li>其他线程{@linkplain线程#中断中断}。 * 当前的线程;或 * * <li>规定的期限已过;或 * * <li>该调用是偶然地(即无故)返回。 * </ul></ul> * * <p>此方法不报告其中的哪种情况,但不报告。 * 方法返回。调用者应重新检查导致 *线程停放在首位。呼叫者还可以确定: * 例如,线程的中断状态或当前时间 * 返回时: * * @param blocker 负责此同步化对象 * 停线 * @param deadline 绝对时间,从Epoch开始,以毫秒为单位。 * 等到 * @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); } /** * 返回提供给最近的阻止者对象。 *调用尚未解锁的公园方法,或为空。 * 如果没有被阻止的话。 返回的值只是一个瞬间的 * 快照 ---- 线程可能已被解封或被封锁了。 * 不同的封锁对象。 * * @param t线程 * @返回封锁者 * 如果参数为空,@throws NullPointerException * @since 1.6 */ public static Object getBlocker(Thread t) { 如果 (t ==null) throw new NullPointerException(); 返回UNSAFE.getObjectVolatile(t, parkBlockerOffset); } /** * 除非有以下情况,否则将禁用当前线程进行线程调度。 * 许可证是可以的。 * * <p>如果许可证可用,则会被消耗掉,然后调用。 * 立即返回;否则,当前线程将被禁用。 *用于线程调度的目的,在以下三种情况之一之前,处于休眠状态。 * <ul> * * <li>其他线程调用{@link #unpark unpark unpark},用 * 当前线程作为目标;或 * * <li>其他线程{@linkplain线程#中断中断}。 *当前的线程;或 * * <li>该调用是偶然地(即无故)返回。 * </ul></ul> * * <p>此方法不报告其中的哪种情况,但不报告。 * 方法返回。调用者应重新检查导致 *线程停放在首位。呼叫者还可以确定: * 例如,返回时线程的中断状态。 */ public static void park() { UNSAFE.park(false, 0L); } /** * 停用当前的线程进行线程调度,最多只需一个线程就可以了。 *规定的等待时间,除非有许可证。 * * <p>如果许可证可用,则会被消耗掉,然后调用。 * 立即返回;否则,当前线程将被禁用。 *用于线程调度的目的,并在四种情况下休眠,直到四种情况之一的 *事情的发生。 * * <ul> * <li>其他线程调用{@link #unpark unpark unpark},用 * 当前线程作为目标;或 * * <li>其他线程{@linkplain线程#中断中断}。 *当前的线程;或 * * <li>指定的等待时间已过;或 * * <li>该调用是偶然地(即无故)返回。 * </ul></ul> * * <p>此方法不报告其中的哪种情况,但不报告。 * 方法返回。调用者应重新检查导致 *线程停放在首位。呼叫者还可以确定: * 例如,线程的中断状态,或中断时间的长短 * 返回时: * * @param nanos 等待的最大纳秒数。 */ public static void parkNanos(long nanos) { 如果 (nanos > 0) UNSAFE.park(false, nanos); } /** * 关闭当前线程的调度功能,直到 * 在规定的最后期限内,除非有许可证。 * * <p>如果许可证可用,则会被消耗掉,然后调用。 * 立即返回;否则,当前线程将被禁用。 *用于线程调度的目的,并在四种情况下休眠,直到四种情况之一的 *事情的发生。 * * <ul> * <li>其他线程调用{@link #unpark unpark unpark},用 * 当前线程作为目标;或 * * <li>其他线程{@linkplain线程#中断中断}。 *当前的线程;或 * * <li>规定的期限已过;或 * * <li>该调用是偶然地(即无故)返回。 * </ul></ul> * * <p>此方法不报告其中的哪种情况,但不报告。 * 方法返回。调用者应重新检查导致 *线程停放在首位。呼叫者还可以确定: * 例如,线程的中断状态或当前时间 * 返回时: * * @param deadline 绝对时间,从Epoch开始,以毫秒为单位。 * 等到 */ public static void parkUntil(long deadline) { UNSAFE.park(true, deadline); } /** * 返回伪随机初始化或更新的二级种子。 * 由于包的访问限制,从ThreadLocalRandom复制过来的。 */ static final int nextSecondarySeed() { int r; Thread t = Thread.currentThread(); 如果 ( (((((r = UNSAFE.getInt(t, SECONDARY)) ) != 0) { r ^= r << 13; /// xorshift r ^= r >>> 17; r ^= r << 5; } 否则如果((((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) ==0) r = 1; ///避免零 UNSAFE.putInt(t, SECONDARY, r); 返回 r; } ///通过本体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); } } }
标签:JUC,code,Thread,调用,park,吊打,源码,线程,unpark 来源: https://www.cnblogs.com/FlyAway2013/p/12655606.html