java编程之美 学习笔记
LockSupport
LockSupport是用来创建锁和其他同步类
的基本线程阻塞原语 ,此类以及每个使用它的线程与一个许可关联。它的主要作用是挂起和唤醒
线程,内部是使用Unsafe
类实现的.
demo例
park()
如果调用park方法的线程已经拿到了LockSupport关联的许可证,则调用LockSupport.park()会立即返回,否则会阻塞。
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
System.out.println("begin park!");
LockSupport.park();
System.out.println("end park!");
});
thread.start();
}
最终程序只会打印begin park
,且一直阻塞在这里。
- 仅在其他线程调用
unpark(thread)
方法将当前线程作为参数,阻塞的线程会返回。 - 或调用阻塞线程的
interrupt()
方法设置中断标识,阻塞线程也会返回。因park()阻塞的线程
被其他线程中断时不会抛出InterruptedException
unpark
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
System.out.println("begin park!");
LockSupport.park();
System.out.println("end park!");
});
thread.start();
TimeUnit.SECONDS.sleep(10);
System.out.println("---------------------afeter sleeep 10s.");
LockSupport.unpark(thread);
/* thread.interrupt();*/
}
打印结果:
源码分析
Unsafe回顾
/**
* 阻塞当前线程
* @param var1 : isAbsolute,表示是否为绝对时间
* @param var2 : time
*
* 当isAbsolute=false时,即不是绝对时间,即为相对时间,此时时间单位为nanos
* - time = 0,表示一直阻塞
* - time > 0,表示time时间段后,阻塞线程会被唤醒
*
* 当isAbsolute=true时,即是绝对时间:
* - time > 0, 这里time是个绝对时间,是将某个时间转换计算为ms后的值,表示当前则色线程到某一个时间点后会被唤醒
*/
public native void park(boolean var1, long var2);
/**
* 唤醒调用 park 后阻塞的线程。
* @param var1 : Thread obj
*/
public native void unpark(Object var1);
LockSupport
public class LockSupport {
private LockSupport() {}
private static void setBlocker(Thread t, Object arg) {
UNSAFE.putObject(t, parkBlockerOffset, arg);
}
//通过诊断工具观察线程阻塞原因
public static Object getBlocker(Thread t) {
if (t == null)
throw new NullPointerException();
return UNSAFE.getObjectVolatile(t, parkBlockerOffset);
}
//无参的park()
public static void park() {
//无限期待阻塞线程
UNSAFE.park(false, 0L);
}
public static void parkNanos(long nanos) {
if (nanos > 0)
//阻塞线程 nanos;
UNSAFE.park(false, nanos);
}
public static void park(Object blocker) {
Thread t = Thread.currentThread();
//设置线程t的parkBlocker
setBlocker(t, blocker);
//挂起线程
UNSAFE.park(false, 0L);
//线程被激活后,清除blocker变量,因为一般线程在阻塞时才分析原因
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);
}
}
/**
* @param blocker
* @param deadline deadline单位为毫秒,epochtime
*/
public static void parkUntil(Object blocker, long deadline) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(true, deadline);
setBlocker(t, null);
}
public static void parkUntil(long deadline) {
UNSAFE.park(true, deadline);
}
//
public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}
}
JDK推荐带有blocker参数的park方法
,且blocker设置为this
.
FIFOMutex
以下是一个先进先出 (first-in-first-out) 非重入锁类的框架.
public class FIFOMutex {
private final AtomicBoolean locked = new AtomicBoolean(false);
private final Queue<Thread> waiters = new ConcurrentLinkedQueue<Thread>();
public void lock() {
boolean wasInterrupted = false;
Thread current = Thread.currentThread();
waiters.add(current);
// 当当前线程不是队首时, 或者 locked为true时,即锁被其他线程获取了;
while (waiters.peek() != current ||
!locked.compareAndSet(false, true)) {
//当前线程挂起
LockSupport.park(this);
//如果当前线程被挂起了,设置中断标识;
if (Thread.interrupted()) {
wasInterrupted = true;
}
}
waiters.remove();
if (wasInterrupted) {
current.interrupt();
}
}
public void unlock() {
locked.set(false);
LockSupport.unpark(waiters.peek());
}
}