Java并发之LockSupport源码解析
LockSupport中主要的两个成员变量
1 | private static final sun.misc.Unsafe UNSAFE; |
- unsafe:全名sun.misc.Unsafe可以直接操控内存,被JDK广泛用于自己的包中,如java.nio和java.util.concurrent。但是不建议在生产环境中使用这个类。因为这个API十分不安全、不轻便、而且不稳定。LockSupport的方法底层都是调用Unsafe的方法实现。
- parkBlocker就是第一部分说到的用于记录线程被谁阻塞的,用于线程监控和分析工具来定位原因的,可以通过LockSupport的getBlocker获取到阻塞的对象。
1 | static { |
从这个静态语句块可以看的出来,先是通过反射机制获取Thread类的parkBlocker字段对象。然后通过sun.misc.Unsafe对象的objectFieldOffset方法获取到parkBlocker在内存里的偏移量,parkBlockerOffset的值就是这么来的.
JVM的实现可以自由选择如何实现Java对象的“布局”,也就是在内存里Java对象的各个部分放在哪里,包括对象的实例字段和一些元数据之类。 sun.misc.Unsafe里关于对象字段访问的方法把对象布局抽象出来,它提供了objectFieldOffset()方法用于获取某个字段相对 Java对象的“起始地址”的偏移量,也提供了getInt、getLong、getObject之类的方法可以使用前面获取的偏移量来访问某个Java 对象的某个字段。
为什么要用偏移量来获取对象?干吗不要直接写个get,set方法。多简单?
仔细想想就能明白,这个parkBlocker就是在线程处于阻塞的情况下才会被赋值。线程都已经阻塞了,如果不通过这种内存的方法,而是直接调用线程内的方法,线程是不会回应调用的。
LockSupport的方法
可以看到,LockSupport中主要是park和unpark方法以及设置和读取parkBlocker方法。
1 | private static void setBlocker(Thread t, Object arg) { |
阻塞线程
park()
1 | public static void park() { |
调用native方法阻塞当前线程。
parkNanos(long nanos)
1 | public static void parkNanos(long nanos) { |
阻塞当前线程,最长不超过nanos纳秒,返回条件在park()的基础上增加了超时返回。
parkUntil(long deadline)
1 | public static void parkUntil(long deadline) { |
阻塞当前线程,知道deadline时间(deadline - 毫秒数)。
JDK1.6引入这三个方法对应的拥有Blocker版本。
park(Object blocker)
1 | public static void park(Object blocker) { |
- 记录当前线程等待的对象(阻塞对象);
- 阻塞当前线程;
- 当前线程等待对象置为null。
parkNanos(Object blocker, long nanos)
1 | public static void parkNanos(Object blocker, long nanos) { |
阻塞当前线程,最长等待时间不超过nanos毫秒,同样,在阻塞当前线程的时候做了记录当前线程等待的对象操作。
parkUntil(Object blocker, long deadline)
1 | public static void parkUntil(Object blocker, long deadline) { |
阻塞当前线程直到deadline时间,相同的,也做了阻塞前记录当前线程等待对象的操作。
唤醒线程
unpark(Thread thread)
1 | public static void unpark(Thread thread) { |
唤醒处于阻塞状态的线程Thread。