LockSupport与线程阻塞唤醒

1. park /unpark 工作机制

  • LockSupport.park()

    阻塞当前线程,直到被 unpark 或线程中断。

  • LockSupport.unpark(Thread t)

    给指定线程发放一个「许可」,让它从 park 中返回。

核心机制:许可机制(类似 0/1 信号量)

LockSupport.park()

尝试拿走这张令牌

  • 当前令牌 = 1:拿走令牌 → 令牌变 0 → 直接放行,不阻塞
  • 当前令牌 = 0:拿不到 → 线程阻塞挂起,原地等着

LockSupport.unpark (线程)

给目标线程发一张令牌

  • 原本 0 → 改成 1
  • 原本已经是 1 → 不变,还是 1,不叠加

场景 1:先 park,后 unpark

  1. 线程 A 执行 park()

    此时许可 = 0,拿不到令牌 → 阻塞卡住

  2. 其他线程执行unpark(A)

    给 A 发许可,许可变成 1

  3. 被卡住的 A 立刻醒来,消耗掉许可(许可变回 0)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.concurrent.locks.LockSupport;

public class ParkUnparkDemo {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
System.out.println("t1 准备阻塞 park");
// 消费许可:无许可 -> 阻塞
LockSupport.park();
System.out.println("t1 被 unpark 唤醒,继续执行");
});

t1.start();
// 主线程休眠 2 秒,让 t1 先执行 park 阻塞
Thread.sleep(2000);

System.out.println("主线程执行 unpark,唤醒 t1");
// 给 t1 发放许可
LockSupport.unpark(t1);
}
}

场景 2:先 unpark,后 park(重点、难点)

  1. 其他线程提前执行 unpark(A)

    A 的许可直接变成 1

  2. 过一会,线程 A 才执行 park()

    一看:有许可(1),直接拿走、消耗掉

    → 完全不阻塞,直接往下执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class UnparkFirstDemo {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1 休眠结束,执行 park");
// 之前已经提前发过许可,直接消费、不阻塞
LockSupport.park();
System.out.println("t1 直接通过,没有被阻塞");
});

t1.start();
// 【关键】先提前发放许可
System.out.println("主线程先执行 unpark(t1)");
LockSupport.unpark(t1);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class NoCumulativeDemo {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
System.out.println("t1 第一次 park");
LockSupport.park(); // 消费唯一许可

System.out.println("t1 第二次 park");
LockSupport.park(); // 没有许可,永久阻塞
});

t1.start();

// 连续多次 unpark,许可只会是 1,不会叠加
LockSupport.unpark(t1);
LockSupport.unpark(t1);
LockSupport.unpark(t1);
System.out.println("连续3次 unpark,许可依旧只有1个");
}
}

2. 与 wait/notify 的核心区别

对比 wait/notify park/unpark
前置条件 必须在 synchronized 内部 任意地方可用
执行顺序 notify 必须在 wait 后,否则永久等待 unpark 可先于 park,不会卡死
目标 随机唤醒一个 / 全部唤醒 精准唤醒指定线程
锁释放 释放锁 不涉及锁,只阻塞线程
中断 不响应中断(只会抛异常) 可响应中断,不会抛异常

一句话总结:

park/unpark 更灵活、更精准、顺序不敏感、无锁限制。

3. AQS 底层依赖的阻塞工具

  • AQS(AbstractQueuedSynchronizer) 是 Java 锁的基石:

    ReentrantLock、CountDownLatch、Semaphore 等都基于它。

  • AQS 内部线程排队、阻塞与唤醒,完全依赖:

    • LockSupport.park()
    • LockSupport.unpark()

所以:

LockSupport 是整个 JUC 同步组件的底层阻塞原语。


LockSupport与线程阻塞唤醒
http://hanqichuan.com/2026/04/15/java并发/LockSupport与线程阻塞唤醒/
作者
韩启川
发布于
2026年4月15日
许可协议