LockSupport工具类定义了一组的公共静态方法,这些方法提供了最基本的线程阻塞和唤醒功能。Java锁和同步器框架的核心工具类AQS:AbstractQueueSynchronizer,就是通过调用LockSupport.park()和LockSupport.unpark()实现线程的阻塞和唤醒。
LockSupport很类似于二元信号量(只有1个许可证可供使用),如果这个许可证还没有被占用,当前线程获取许可并继续执行。如果许可已经被占用,当前线程阻塞,等待获取许可。但是这个许可是不能叠加的,“许可”是一次性的。
比如线程B连续调用了三次unpark函数,当前线程A调用park函数就使用掉这个“许可”,如果线程A再次调用park,则进入等待状态。
注意:unpark函数可以先于park调用。比如线程B调用unpark函数,给线程A发了一个“许可”,那么当线程A调用park时,它发现已经有“许可”了,那么它会马上再继续运行。
park和unpark的灵活之处
上面已经提到了,unpark函数可以先于park调用,这个正是它们的灵活之处。
一个线程它有可能在别的线程unpark之前,或者之后,或者同时调用park,那么因为park的特性,它可以不用担心自己的park的时序问题,否则,如果park必须要在unpark之前,那么给编程带来很大的麻烦!!
考虑一下,两个线程同步,要如何处理?
在Java5里是用wait/notify/notifyAll来同步的。wait和notify机制有个很蛋疼的地方是,比如线程B要用notify通知线程A,那么线程B要确保线程A已经在wait调用上等待了,否则线程A可能永远都在等待。编程的时候就会很蛋疼。
另外,是调用notify,还是notifyALL?
notify只会唤醒一个线程,如果错误地有两个线程在同一个对象上wait等待,那么又悲剧了。为了安全起见,貌似只能调用nofityAll了。
park和unpark模型真正解耦了线程之间的同步,线程之间不再需要一个Objec或者其他变量来存储状态,不再需要关心对方的状态。
LockSupport API的使用
方法名 | 方法摘要 |
---|---|
static void park() | 阻塞当前线程,如果调用了unpark(Thread thread)方法或者当前线程被中断,才能park()方法返回 |
static void unpark() | 唤醒处于阻塞状态的线程thread |
static void parkNanos(long nanos) | 阻塞当前线程,最长不超过nanos纳米,返回条件在park()的基础上增加了超时返回 |
static void parkUntil(long dealine) | 在指定的时限前阻塞当前线程 |
LockSupport 简单使用
public static void main(String[] args) {
Executor executor = Executors.newFixedThreadPool(2);
Thread mainThread = Thread.currentThread() ;
executor.execute(()->{
try {
Thread.sleep(3000L);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("start unpark main thread");
LockSupport.unpark(mainThread);
System.out.println("unpark main thread over");
});
System.out.println("before park");
LockSupport.park();
System.out.println("after park ");
}
运行结果:
先释放许可,再获取许可
@Test
public void test1() {
Thread thread = Thread.currentThread();
LockSupport.unpark(thread);//释放许可
LockSupport.park();// 获取许可
System.out.println("b");
}
中断响应
public static void main(String[] args) {
Executor executor = Executors.newFixedThreadPool(2);
Thread mainThread = Thread.currentThread() ;
executor.execute(()->{
try {
Thread.sleep(3000L);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("start interrupt main thread");
mainThread.interrupt();
System.out.println("interrupt main thread over");
});
System.out.println("before park");
LockSupport.park();
LockSupport.park();
System.out.println("after park ");
}
运行截图: