从上一篇文章中的JDK的延迟队列中,最终是通过LockSupport.park实现线程的等待,那么底层是如何实现等待和超时等待的
LockSupport的park和unpark的方法
1 | arduino复制代码public static void park() { |
从上面可以看到实际LockSupport.park是通过Unsafe的的park方法实现,从下面的方法可以看出这个是一个native方法.
1 | java复制代码/** |
JVM的Unsafe的park方法
从下面JDK中代码中可以thread的Parker的对象的park方法进行一段时间的等待。
1 | scss复制代码UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time)) { |
Thread.hpp的文件中内部定义的Park对象
1 | arduino复制代码 private: |
下面是Os_posix.cpp中是Linux中实现的Park的park的实现方式
- 首先将_counter的变量通过CAS设置为0,返回就旧的值,如果之前是大于0,则说明是允许访问,不用阻塞,直接返回。
- 获取当前线程。
- 判断线程是否是中断中,如果是,则直接返回,(也就是说线程处于中断状态下会忽略park,不会阻塞等待)
- 判断如果传入的time参数小于0 或者 是绝对时间并且time是0,则直接返回,(上面的Unsafe调用park传入的参数是 false、0,所以不满足这种情况)
- 如果time大于0,则转换成绝对时间。
- 创建ThreadBlockInVM对象,并且调用pthread_mutex_trylock获取线程互斥锁,如果没有获取到锁,则直接返回,
- 判断_counter变量是否大于0,如果是,则重置_counter为0,释放线程锁,直接返回。
- 调用 OrderAccess::fence(); 加入内存屏障,禁止指令重排序,确保加锁和释放锁的指令的顺序。
- 创建OSThreadWaitState对象,
- 判断time是否大于0,如果是0,则调用pthread_cond_wait进行等待,如果不是0,然后调用pthread_cond_timedwait进行时间参数为absTime的等待,
- 调用pthread_mutex_unlock进行释放_mutex锁,
- 再次调用OrderAccess::fence()禁止指令重排序。
1 | scss复制代码 // Parker::park decrements count if > 0, else does a condvar wait. Unpark |
Linux操作系统是如何实现pthread_cond_timedwait进行时间等待的
pthread_cond_timedwait函数位于glibc中pthread_cond_wait.c, 可以看到是调用
__pthread_cond_wait_common实现
1 | arduino复制代码/* See __pthread_cond_wait_common. */ |
下面__pthread_cond_wait_common是实现通过__futex_abstimed_wait_cancelable64实现时间等待
1 | arduino复制代码static __always_inline int |
__futex_abstimed_wait_cancelable64是调用__futex_abstimed_wait_common
1 | arduino复制代码int |
__futex_abstimed_wait_common下面则是通过判断平台是64位或者32位,调用__futex_abstimed_wait_common64或者__futex_abstimed_wait_common32
1 | arduino复制代码static int |
__futex_abstimed_wait_common64是调用INTERNAL_SYSCALL_CANCEL宏定义实现
1 | arduino复制代码static int |
系统调用的的宏定义
1 | ini复制代码/* Issue a syscall defined by syscall number plus any other argument |
总结
主要对LockSupport的park等待实现的底层实现的浅析,针对于Linux的系统调用还没有找到源码,后续会继续跟踪,希望有读者知道的满帆可以告知下,谢谢。
本文转载自: 掘金