locksupport.getblocker(thread) 仅返回显式设置的 blocker 对象,非 jvm 自动推断的阻塞源;其用途是调试标记,依赖 aqs 等手动设置,null 表示未设而非未阻塞。

LockSupport.getBlocker(Thread) 并不能可靠获取线程“当前被阻塞的具体对象引用”——它返回的是由 Unsafe.park(boolean, long) 调用前,通过 Unsafe.setBlocker 显式设置的 blocker 对象,而非 JVM 自动推断的、语义上“导致阻塞”的锁或同步器实例。
getBlocker 的真实作用:手动标记阻塞原因
该方法的设计初衷是为调试和监控提供线索,而非自动追踪阻塞源头。JVM 本身不分析线程为何 park,也不自动关联 ReentrantLock、Semaphore 等同步组件。是否设置 blocker、设成什么,完全取决于调用 park 的代码逻辑:
- Java 标准库中,
AbstractQueuedSynchronizer(AQS)子类(如 ReentrantLock、CountDownLatch)在调用LockSupport.park(this)前,会主动执行Unsafe.setBlocker(t, this),把当前 AQS 实例(即锁对象)设为 blocker; - 但若某段自定义代码直接调用
LockSupport.park(null)或park()(无参数),blocker 就保持为null; - 如果调用方传入了错误对象(比如传入一个临时字符串),getBlocker 返回的也不是“真正阻塞它的对象”,只是那个被误设的值。
如何正确使用 getBlocker 分析阻塞对象
要借助 getBlocker 定位问题,需满足两个前提:目标线程确实由标准同步器 park,且你有权限访问其 Thread 实例:
- 用
Thread.getAllStackTraces().keySet()或jstack找到处于WAITING (parking)或BLOCKED状态的线程; - 对目标线程调用
LockSupport.getBlocker(thread); - 若返回非 null,大概率是该线程正在等待的那个 AQS 实例(例如
ReentrantLock$NonfairSync@123abc),可进一步检查该对象状态(如是否已被其他线程持有、是否发生死锁); - 若返回 null,不代表没被阻塞,只说明 park 时未设置 blocker —— 此时需结合线程栈(尤其是 park 调用栈上方的 lock()、await() 等方法)反推阻塞点。
常见误区与限制
开发者容易高估 getBlocker 的能力,需注意:
- 它不是“阻塞锁发现器”:无法穿透 synchronized、Object.wait()、Channel I/O 等机制;这些场景下 blocker 恒为 null;
- 无法反映实时所有权:即使 getBlocker 返回一个 ReentrantLock 实例,也不能直接判断该锁是否仍被持有 —— 需额外调用其
isLocked()或getHoldCount()等方法验证; - 多层封装下易失效:若同步逻辑被 Spring AOP、自定义 Executor 或协程框架包裹,park 可能发生在代理层,blocker 可能指向代理对象而非原始锁。
替代方案:更可靠的阻塞分析手段
依赖 getBlocker 有局限,生产环境推荐组合使用:
-
jstack -l
:输出带锁信息的完整线程快照,明确显示 - waiting to lock或- locked的对象地址; - JDK Mission Control / JFR:开启
jdk.ThreadPark事件,记录 park 时的 blocker、栈帧和持续时间; - 在关键同步器上添加日志或使用
java.util.concurrent.locks.Lock.getQueueLength()等可观测性 API 辅助判断; - 对于自定义 park 场景,务必在 park 前调用
Unsafe.setBlocker(Thread.currentThread(), yourMeaningfulObject),否则 getBlocker 失去意义。










