前言
本篇文章主要分析
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




随时随地看视频