目录
底层源码分析
线程状态变化
许可证机制
中断处理
底层源码分析
public class LockSupport {
// Unsafe实例
private static final Unsafe U = Unsafe.getUnsafe();
// Thread对象中parkBlocker字段的偏移量
private static final long PARKBLOCKER = U.objectFieldOffset(Thread.class, "parkBlocker");
// 私有构造函数,防止实例化
private LockSupport() {}
}
由源码中可以看出,LockSupport类有一个Unsafe对象的静态属性,通过Unsafe类的静态方法getUnsafe获取的,而在Unsafe类中就有个静态属性Unsafe,用的是单例模式饿汉式创建。
也由此可得知,LockSupport的底层其实就是依靠Unsafe类提供的方法。
接下来看看核心方法。
public class LockSupport {
// park方法实现
public static void park() {
// 调用Unsafe的park方法
U.park(false, 0L);
}
// 带blocker的park方法
public static void park(Object blocker) {
// 获取当前线程
Thread t = Thread.currentThread();
// 设置blocker
setBlocker(t, blocker);
// 执行park操作
U.park(false, 0L);
// 清除blocker
setBlocker(t, null);
}
// unpark方法实现
public static void unpark(Thread thread) {
if (thread != null)
U.unpark(thread);
}
}
可以看到实际上就是调用了unsafe类的park和unpark方法,至于这个blocker对象也是大有用处的,想要了解的读者可以看看这篇文章LockSupport底层源码分析(二)-CSDN博客,先接着往下看。
unsafe类的park方法是一个native本地方法,底层是c/c++实现的。
// Hotspot底层实现(C++代码)
void Parker::park(bool isAbsolute, jlong time) {
// 获取Parker对象
Parker* p = Parker::fromThread(thread);
// 检查_counter
if (p->_counter > 0) {
// 已经有unpark了,直接返回
p->_counter = 0;
return;
}
// 设置等待状态
ThreadState old = thread->set_state(WAITING);
// 等待条件变量
while (p->_counter == 0) {
if (time > 0) {
// 带超时的等待
p->_cond.wait(time);
} else {
// 无限等待
p->_cond.wait();
}
}
// 恢复线程状态
thread->set_state(old);
// 重置计数器
p->_counter = 0;
}
在上可以看到c++源码实现的一个情况,获取到thread关联的parker对象,检查他的一个counter属性是不是大于0,大于0则已经有unpark了,直接返回。不然就设置线程状态,再调用wait方法进行等待,如果被unpark了或者是到时间了,再恢复线程状态,重置计时器。
这也说明了为什么park方法不会被interrupt打断,因为他也根本没做任何的响应操作。
再看看下面的代码实现。
线程状态变化
// 线程状态转换示意
public class ThreadStateDemo {
public void demonstrateThreadStates() {
Thread t = new Thread(() -> {
// 运行状态 RUNNABLE
LockSupport.park();
// 等待状态 WAITING
// 被unpark后恢复到 RUNNABLE
});
t.start();
// 某个时刻调用unpark
LockSupport.unpark(t);
}
}
许可证机制
public class PermitExample {
public void demonstratePermit() {
Thread t = new Thread(() -> {
// 1. 先park
System.out.println("准备park");
LockSupport.park();
System.out.println("park结束");
// 2. 再次park
System.out.println("再次park");
LockSupport.park();
System.out.println("第二次park结束");
});
t.start();
// 提前调用unpark
LockSupport.unpark(t);
// 线程启动后会直接通过第一个park
Thread.sleep(1000);
// 再次unpark
LockSupport.unpark(t);
// 线程通过第二个park
}
}
中断处理
public class InterruptExample {
public void demonstrateInterrupt() {
Thread t = new Thread(() -> {
try {
// park不响应中断,但会记录中断状态
LockSupport.park();
// 检查中断状态
if (Thread.interrupted()) {
System.out.println("被中断");
return;
}
// 继续执行
doWork();
} catch (Exception e) {
e.printStackTrace();
}
});
t.start();
// 中断线程
t.interrupt();
}
}