AQS理解之一,基础知识——LockSupport
LockSupport类位于java.util.concurrent包下。
顾名思义,就是一个实现锁的辅助类。
来看下他的类结构:
其中的变量都是通过UNSAFE类来赋值,代码如下:
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();
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); }
}
parkBlockerOffset 是Thread类中的parkBlocker参数,其他参数类似。
parkBlockerOffset参数设置之后可以在jstack的时候对给这个变量设置了值的线程进行观察。
方法是park()和unpark(Thread t)和这两个方法的一些带时间参数方法。
通过看这个类的注释,可以知道park 和unpark实际上是对线程的阻塞与解除阻塞。
park: 阻塞线程,线程在一下三种情况下会被打开:
1.调用unpark方法,释放该线程的许可。
2.该线程被中断。
3.时间到期。
LockSupport的park和unpark操作的实际动作。
1.调用unpark
如果没有可用线程,则给定许可(permit就变成1(不会累计))
如果有线程被阻塞,解除锁,同时park返回。
如果给定线程没有启动,则该操作不能保证有任何效果.
2.调用park,则会检测permit是否为1。
如果为1则将permit变成0;
如果不为1,则堵塞线程,直到permit变为1.
我们知道wait和notify也可以实现对线程的阻塞和解除,他们的区别主要在于:
1,unpark会直接指定要解除阻塞的线程,而notify需要知道有一个确定的线程在wait,如果有多个线程在阻塞,则不能确定知道哪个会被解除阻塞。
2,wait和notify有先后顺序,即必须先wait,再notify才能解除,而park和unpark则没有,可以先给权限,再阻塞,阻塞会直接返回。
3,wait时线程如果被interrupt,会报错InterruptedException,而park时则会正常结束。
4,wait/notify面向对象,而LockSupport面向线程