Fork me on GitHub

【Java多线程】JUC锁 03. LockSupport

LockSupport

  • 基本线程阻塞原语
  • LockSupport中的park() 和 unpark() 的作用分别是阻塞线程和解除阻塞线程,而且park()和unpark()不会遇到“Thread.suspend 和 Thread.resume所可能引发的死锁”问题。 因为park() 和 unpark()有许可的存在;调用 park() 的线程和另一个试图将其 unpark() 的线程之间的竞争将保持活性。

1. 源码解读

1
private LockSupport() {}	 //私有构造函数,无法被实例化

1.1 成员变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private static final sun.misc.Unsafe 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); }
}

1.2 核心方法

1.2.1 park()

三种形式的park()还各支持一个blocker对象参数,即有没有设置线程的parkBlocker字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//阻塞当前线程,在阻塞当前线程的时候做了记录当前线程等待的对象操作
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);
setBlocker(t, null); //可运行后清除blocker
}

//阻塞当前线程,最长等待时间不超过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时间,也做了阻塞前记录当前线程等待对象的操作
public static void parkUntil(Object blocker, long deadline) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(true, deadline);
setBlocker(t, null);
}

线程可重新运行的情况:

  • 其他某个线程将当前线程作为目标调用 unpark
  • 其他某个线程中断当前线程 interrupt()
  • 该调用不合逻辑地(即毫无理由地)返回

wait()park()区别在于:

  • wait() 阻塞线程前,必须通过synchronized获取同步锁
  • 更加灵活。使用park/unpark,不会造成由wait/notify调用顺序不当所引起的阻塞

1.2.2 unpark(Thread thread)

1
2
3
4
5
//解除阻塞线程
public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}

2. 参考资料

【JUC】JDK1.8源码分析之LockSupport(一)

Java多线程系列–“JUC锁”07之 LockSupport