前言
本篇文章主要分析
LockSupport
,在系列文章中的AQS
就有用到. 本文会通过源码分析中看看LockSupport
如何使用.
本文代码: 代码下载
LockSupport
源码
LockSupport
在java.util.concurrent.locks
包中,总共的代码就一两百行左右,如下:
import java.lang.reflect.Field;import sun.misc.Unsafe;public class LockSupport { private LockSupport() {} private static void setBlocker(Thread t, Object arg) { UNSAFE.putObject(t, parkBlockerOffset, arg); } public static void unpark(Thread thread) { if (thread != null) UNSAFE.unpark(thread); } 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); } public static Object getBlocker(Thread t) { if (t == null) throw new NullPointerException(); return UNSAFE.getObjectVolatile(t, parkBlockerOffset); } 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); } static final int nextSecondarySeed() { int r; Thread t = Thread.currentThread(); if ((r = UNSAFE.getInt(t, SECONDARY)) != 0) { r ^= r << 13; // xorshift r ^= r >>> 17; r ^= r << 5; } else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0) r = 1; // avoid zero UNSAFE.putInt(t, SECONDARY, r); return r; } // Hotspot implementation via intrinsics API private static final sun.misc.Unsafe UNSAFE; private static final long parkBlockerOffset; private static final long SEED; private static final long PROBE; private static final long SECONDARY; static { try { //UNSAFE = sun.misc.Unsafe.getUnsafe(); 源码 Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); UNSAFE = (Unsafe)f.get(null); Class<?> tk = Thread.class; 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); } } }
代码中只有在获得
UNSAFE
的时候改成了反射实现,其余的都是维持原样.因为需要有特定的classloader
才可以加载Unsafe
类,因此在自己的代码中用反射来拿到实例对象.
另外Unsafe
类的作用会有专门博客分析,暂时可以认为该类可以利用底层的方法成功操作.
注意:tk
是Thread.class
,操作的是Thread
类的成员变量.
从上面源码中可以看到:
1. 只有一个构造方法并且还是私有的,所以没办法
new
出一个对象.
2. 方法几乎都是静态的,所以通过类就可以调用.
3. 所有的park*
方法最终都会调用UNSAFE.park(boolean, long)
方法,unpark
最终还是会调用UNSAFE.unpark(Thread)
方法.
4. 有一个setBlocker
和getBlocker
方法.
所以从该源码中也具体看不出逻辑和实现,所以看看
Unsafe
中park
和unpark
方法.
sun.misc.Unsafe
中的park
和unpark
在
sun.misc.Unsafe
中的源码
public native void unpark(Object paramObject);public native void park(boolean paramBoolean, long paramLong);
这个是本地方法,实现如下:
源码在park.hpp(这个是1.7的,没有找到1.8的,有地址,但是还是没有找到具体的类的位置)
每个线程都有一个Parker
实例,每个实例有一个_counter
属性,初始化值为0
.
图片.png
对应的
park
和unpark
源码, 源码文件
park方法
图片.png
isAbsolute
表示是否是绝对时间,可以看到parkUntil(long deadline)
调用的时候表示的是绝对时间
1. 如果
_counter
变量大于0,便可以获得许可permit
.
2. 可选性的优化,在阻塞前检查一下中断状态.如果当前线程处于中断状态,则直接返回._counter
没有变化,此时的_counter
处于
3. 检查一下时间是否到时,比如那种超时获取许可的方法等,另外如果time
> 0,则调用unpackTime(&absTime, isAbsolute, time);
方法
图片.png
4. 生成一个ThreadBlockInVM
5. 这句话我还没有弄明白
6. 再次检查_counter
是不是大于0,如果是的话表示可以获得许可并且把_counter
并且unlock_mutex
.
图片.png
作者:nicktming
链接:https://www.jianshu.com/p/ca3e8a5b7a1d