Java LockSupport

提供线程阻塞原语的工具类

基本实现


LockSupport从名字看出是提供锁支持的,实现上定位是静态工具类

LockSupport.java
1
2
3
4
public class LockSupport {
private LockSupport() {}
//...
}

底层基于UNSAFE实现,操控对象是线程

LockSupport.java
1
2
3
4
5
6
7
8
9
10
11
12
13
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
//操作对象是线程类
Class<?> tk = Thread.class;
//对象字段parkBlocker
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); }
}

基本操作是park,阻止当前线程参与调度,符合停车语义,提供定时和非定时操作

LockSupport.java
1
2
3
4
5
6
7
8
9
10
11
12
public static void park() {
UNSAFE.park(false, 0L);
}
//停指定纳秒
public static void parkNanos(long nanos) {
if (nanos > 0)
UNSAFE.park(false, nanos);
}
//停到指定毫秒时间戳
public static void parkUntil(long deadline) {
UNSAFE.park(true, deadline);
}

还可以在park时传入一个blocker对象,会设置到线程类中
对象可以取出,监控诊断工具可以通过对象提供更多信息,比如在dump中观察到,唤醒后会清空blocker对象

LockSupport.java
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
26
public static Object getBlocker(Thread t) {
if (t == null)
throw new NullPointerException();
return UNSAFE.getObjectVolatile(t, parkBlockerOffset);
}
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);
//清空
setBlocker(t, null);
}
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);
}
}
public static void parkUntil(Object blocker, long deadline) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(true, deadline);
setBlocker(t, null);
}

解除方法只有一个,其他线程传入目标线程对目标进行唤醒

LockSupport.java
1
2
3
4
public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}

park可能自己解除,比如遇到中断或者根本没有原因,需要在循环条件检测下使用
遇到中断也不会抛异常,只会解除,中断由线程自行检查

Sample
1
2
3
4
while (!canProceed()) {
//...
LockSupport.park(this);
}

使用案例


文档自带例程,线程执行队列

Sample
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
26
27
28
29
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);

// 不是队列头或者没拿到锁就阻塞
// 循环条件检查
while (waiters.peek() != current || !locked.compareAndSet(false, true)) {
LockSupport.park(this);
if (Thread.interrupted()) // 解除后先检测中断
wasInterrupted = true;
}

waiters.remove();
if (wasInterrupted)
current.interrupt();
}

public void unlock() {
//清空锁状态
locked.set(false);
//解除排头线程
LockSupport.unpark(waiters.peek());
}
}

对比其他机制


LockSupport不涉及锁,单纯的让线程等待,是否放锁由外部逻辑,比如Condition.await

与WaitNotify,Condition比较

  • Wait-Notify机制让线程等待在对象锁monitor上
  • Condition机制让线程等待在显式锁上,底层基于LockSupport

与Thread.sleep比较

  • Thread.sleep是定时自唤醒场景,必须传入时间
  • LockSupport更加灵活,可以长期等待,可以主动唤醒