LockSupport
LockSupport是一个线程阻塞工具,它可以在线程内任意位置让线程阻塞。
优点
- 跟Thread.suspend()相比,它弥补了由于resume()发生在前,导致线程无法继续执行的情况。
- 与Object.wait()相比,它不需要先获得某个对象的锁,也不会抛出InterruptedException异常。
特点
LockSupport为每个线程准备了一个许可,如果许可可用,那么park()函数会立即返回,并且消费这个许可(也就是将许可变得不可用),如果许可不可用,那么就会阻塞。而unpark()则使得一个许可变为可用(但是和信号量不同的是,许可不能累加,你不可能拥有超过一个许可,它永远只有一个)。
源码解读
public class LockSupport {
// 这里用了private修饰,使得LockSupport无法被实例化,即不能使用new 操作费
private LockSupport() {}
// 设置一个阻塞对象,用来标识当前线程在等待的对象,主要用来问题排查和系统监控。
private static void setBlocker(Thread t, Object arg) {
//UNSAFE.putObject 是java原始方法
UNSAFE.putObject(t, parkBlockerOffset, arg);
}
//如果线程的许可是不可用的,那么就使得线程的许可可以用。
// 如果线程因为park方法而阻塞,那么调用此方法,线程将会被唤醒。
// 如果线程还没有启动,那么调用该方法不能保证能有什么效果。
public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}
//在park()方法的基础上,增加了标识当前线程在等待的对象。
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);
setBlocker(t, null);
}
//在parkNanos(long nanos)方法的基础上,增加了标识当前线程在等待的对象。
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);
}
}
// 在parkUntil(long deadline)方法的基础上,增加了标识当前线程在等待的对象。
public static void parkUntil(Object blocker, long deadline) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(true, deadline);
setBlocker(t, null);
}
// 如果park()方法造成当前线程阻塞,而该线程还没有被唤醒,那么返回传递给park()方法的阻塞对象。如果该线程没有被阻塞,那就返回null;
public static Object getBlocker(Thread t) {
if (t == null)
throw new NullPointerException();
return UNSAFE.getObjectVolatile(t, parkBlockerOffset);
}
// 如果许可是可用的,那么许可会被消费,然后pack方法会立即返回。(unpark方法会使得许可可用)
//作用阻塞当前线程,如果调用unpark(Thread thread)方法或者当前线程中断(不会抛出异常,只会默默的返回),才能从park方法返回。
public static void park() {
UNSAFE.park(false, 0L);
}
// 在park()的基础上增加了超时返回。
public static void parkNanos(long nanos) {
if (nanos > 0)
UNSAFE.park(false, nanos);
}
// 在park()的基础上增加了到deadline时间返回。
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;
UNSAFE.putInt(t, SECONDARY, r);
return r;
}
// 通过内置API实现Hotspot
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); }
}
}
Demo1——LockSupport.getBlocker获取阻塞对象
public class LockSupportDemo1 {
private static Object u = new Object();
private static ChangeObjectThread t1 = new ChangeObjectThread("t1");
private static class ChangeObjectThread extends Thread {
public ChangeObjectThread(String name) {
super.setName(name);
}
@Override
public void run() {
LockSupport.park(u);
}
}
public static void main(String[] args) throws InterruptedException ,Exception{
t1.start();
Thread.sleep(100);
System.out.println(LockSupport.getBlocker(t1));
LockSupport.unpark(t1);
t1.join();
System.out.println(LockSupport.getBlocker(t1));
}
}
结果如下:
java.lang.Object@2401f4c3
null
Demo1—— unpark方法在park方法之前调用
LockSupport.unpark()可以在LockSupport.park()方法前调用,不会造成线程阻塞,原因是,LockSupport.unpark方法之后,许可已可用,后面在调用LockSupport.park方法,LockSupport.park方法会直接返回。
public class LockSupportDemo2 {
private static Object u = new Object();
private static ChangeObjectThread t1 = new ChangeObjectThread("t1");
private static class ChangeObjectThread extends Thread {
public ChangeObjectThread(String name) {
super.setName(name);
}
@Override
public void run() {
try {
Thread.currentThread().sleep(1000);
System.out.println("park()方法被调用");
LockSupport.park(u);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException, Exception {
t1.start();
LockSupport.unpark(t1);
System.out.println("unpark()被调用");
t1.join();
}
}
结果如下:
unpark()被调用
park()方法被调用