标签:pre private hotspot 技术 bubuko png 偏移地址 strong .com
目录
LockSupport是Java6引入的一个工具类, 用于挂起和唤醒线程;
LockSupport 通过提供park() 和 unpark() 方法实现阻塞线程和解除线程阻塞, 实现阻塞与解除阻塞是基于许可(permit), permit相当于一个信号量,只能取0和1, 默认为0;
park()
: 若permit为1, 则permit减1为0; 若permit为0, 则阻塞当前线程;unpark(Thread)
: 若permit为0, permit加1; 若permit为1, permit不变; 但效果都是唤醒指定线程;由于permit默认为0, 因此一般是先调用park()
之后, 当前线程进入阻塞, 然后等待其他线程调用unpark(Thread)唤醒, 或者遇到中断会被唤醒;
LockSupport 是基于 sun.misc.Unsafe 实现的;
parkBlockerOffset 存储Thread类对象中parkBlocker字段的偏移量;
Thread类中, parkBlocker用于存储引起线程阻塞的对象(即: 线程所等待的资源); parkBlocker字段是特地为park()设计的, 在park()调用后, 通过调用setBlocker(Thread t, Object arg)设置线程所等待的资源, 此时用jstack工具进行堆栈分析时, 可以看到该阻塞的线程正在等待的资源arg;
private static final sun.misc.Unsafe UNSAFE;
private static final long parkBlockerOffset;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> tk = Thread.class;
parkBlockerOffset = UNSAFE.objectFieldOffset
(tk.getDeclaredField("parkBlocker"));
...
} catch (Exception ex) { throw new Error(ex); }
}
getBlocker 与 setBlocker 使用Unsafe类通过内存偏移量设置的原因:
因为要设置的parkBlocker的线程已经被阻塞了, 通过调用Thread对象的set方法由于阻塞无法被执行; 然而使用Unsafe类通过内存偏移地址设置并不受Thread对象被阻塞的影响;
/**
* 唤醒线程 t
* @param t 想要唤醒的线程
* @return 返回parkBlocker对象
*/
public static Object getBlocker(Thread t) {
if (t == null)
throw new NullPointerException();
return UNSAFE.getObjectVolatile(t, parkBlockerOffset);
}
/**
* 设置 parkBlocker的值
* @param t 被阻塞的线程
* @param arg 引起线程阻塞的资源
*/
private static void setBlocker(Thread t, Object arg) {
// Even though volatile, hotspot doesn't need a write barrier here.
UNSAFE.putObject(t, parkBlockerOffset, arg);
}
内部实现源码:
public static void park(Object blocker) {
Thread t = Thread.currentThread(); // 获取当前线程
setBlocker(t, blocker); // 设置引起当前线程阻塞的资源
UNSAFE.park(false, 0L); // 将当前线程阻塞
setBlocker(t, null); // 该线程被唤醒后, 将blocker置为null
}
// 阻塞当前线程, 最长不超过nanos纳秒
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);
}
}
// 阻塞当前线程, 知道deadline时间(从1970年开始到deadline时间的毫秒数)
public static void parkUntil(long deadline) {
UNSAFE.park(true, deadline);
}
public static void parkUntil(Object blocker, long deadline) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(true, deadline);
setBlocker(t, null);
}
标签:pre private hotspot 技术 bubuko png 偏移地址 strong .com
原文地址:https://www.cnblogs.com/jxkun/p/9375036.html