java并发编程之LockSupport

本文深入解析LockSupport的内部实现机制,包括如何通过park和unpark方法阻塞与唤醒线程,以及HotSpot虚拟机中Parker类的具体实现细节。

LockSupport,构建同步组件的基础工具,帮AQS完成相应线程的阻塞或者唤醒的工作。

LockSupport源码分析

LockSupport定义了一组以park开头的方法来阻塞当前线程,unpark来唤醒被阻塞的线程。

阻塞线程

  • park()实现
public static void park() {
    UNSAFE.park(false, 0L);
}

调用native方法阻塞当前线程。

  • parkNanos(long nanos)实现
public static void parkNanos(long nanos) {
    if (nanos > 0)
        UNSAFE.park(false, nanos);
}

阻塞当前线程,最长不超过nanos纳秒,返回条件在park()的基础上增加了超时返回。

  • parkUntil(long deadline)实现
public static void parkUntil(long deadline) {
    UNSAFE.park(true, deadline);
}

阻塞当前线程,知道deadline时间(deadline - 毫秒数)。

在java6之后在park系列方法新增加了入参Object blocker,用于标识阻塞对象,该对象主要用于问题排查和系统监控。

park(Object blocker)实现

public static void park(Object blocker) {
    Thread t = Thread.currentThread();
    setBlocker(t, blocker);
    UNSAFE.park(false, 0L);
    setBlocker(t, null);
}
  1. 记录当前线程等待的对象(阻塞对象);
  2. 阻塞当前线程;
  3. 当前线程等待对象置为null。

parkNanos(Object blocker, long 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);
    }
}

阻塞当前线程,最长等待时间不超过nanos毫秒,同样,在阻塞当前线程的时候做了记录当前线程等待的对象操作。

parkUntil(Object blocker, long deadline)

public static void parkUntil(Object blocker, long deadline) {
    Thread t = Thread.currentThread();
    setBlocker(t, blocker);
    UNSAFE.park(true, deadline);
    setBlocker(t, null);
}

阻塞当前线程直到deadline时间,相同的,也做了阻塞前记录当前线程等待对象的操作。

到这里,问题来了,为什么在java6要在入参引入blocker呢?blocker的作用到底是什么?

先看看线程dump的结果:
线程dump结果对比

从线程dump结果可以看出:
有blocker的可以传递给开发人员更多的现场信息,可以查看到当前线程的阻塞对象,方便定位问题。所以java6新增加带blocker入参的系列park方法,替代原有的park方法。

唤醒线程

  • unpark(Thread thread)实现
public static void unpark(Thread thread) {
    if (thread != null)
        UNSAFE.unpark(thread);
}

唤醒处于阻塞状态的线程Thread。

从源码不难发现,LockSupport所有的方法都是调用native的park和unpark实现的,接下来我们具体看看HotSpot中的park/unpark的具体实现。

HotSpot里的park/unpark

在HotSpot中,每个java线程都有一个Parker的实例,Parker的定义是这样子的:
Parker定义
从Parker定义不难看出:
1. 定义私有属性_counter:可以理解为是否可以调用park的一个许可证,只有_count > 0的时候才能调用;
2. 提供public方法park和unpark支撑阻塞/唤醒线程;
3. Parker继承PlatformParker:
PlatformParker定义
从PlatformParker的定义可以看出,Parker实际上是利用Posix的mutex,condition来实现的。

HotSpot park实现
1. 尝试是否能可以调用park,如果_counter > 0,可以调用,将_counter置为0,返回;
park步骤1具体实现
2. 步骤1不成功,构造当前线程的ThreadBlockInVM,检查_counter > 0是否成立,成立则将_counter设置为0,unlock mutex,返回;
park步骤2具体实现
3. 步骤2不成功,根据等待时间调用不同的等待函数等待,如果等待返回正确,将_counter置为0,unlock mutex,返回,park调用成功。
park步骤3具体实现

相比之下,unpark的实现就简单多了。

HotSpot unpark实现
unpark实现

  1. 将_counter置为1;
  2. 判断之前_counter的值:
    • 小于1时,调用pthread_cond_signal唤醒在park中等待的线程;
    • 等于1时,unlock mutex,返回。

**总结:**HotSpot Parker用condition和mutex维护了一个_counter变量,park时,变量_counter置为0,unpark时,变量_counter置为1。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值