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); }
}
}