介绍
LockSupport可以在线程内任意位置让线程阻塞,定义了一组公共静态方法提供最基本的线程阻塞和唤醒功能。
LockSupport类使用类似信号量的机制,LockSupport.unpark()方法使得一个许可变为可用,阻塞的park()方法发现许可可用会立即返回并且会将许可变为不可用。
和信号量不同的是它为每个线程准备一个许可,当执行unpark()方法时,执行一次和执行多次效果是一样的,不会累加可用许可的数量,只会使一个许可可用。由于这种特性,则即使unpark()方法发生在park()方法之前也可正常执行。
LockSupport类静态方法
相关静态方法如下:
//阻塞当前线程(当调用unpark(Thread thread)或者当前线程被中断才返回)
public static void park()
//阻塞当前线程,增加了超时饭回,不超过nanos纳秒
public static void parkNanos(long nanos)
//阻塞当前线程,直到deadline时间(从1970年开始到deadline时间的毫秒数)
public static void parkUntil(long deadline)
//唤醒处于阻塞状态的线程thread
public static void unpark(Thread thread)
在java 6中新增了另外的三个park方法,多了一个类型为Object的blocker参数,用来标识当前线程等待的对象:
public static void park(Object blocker)
public static void parkNanos(Object blocker, long nanos)
public static void parkUntil(Object blocker, long deadline)
上面三个方法的增加主要为了便于问题排查和监控。我们可以通过线程dump结果可以定位到阻塞线程的对象。
简单示例
public class LockSupportDemo {
public static final Object u = new Object();
static ChangeObjectThread t1 = new ChangeObjectThread("t1");
static ChangeObjectThread t2 = new ChangeObjectThread("t2");
public static class ChangeObjectThread extends Thread {
public ChangeObjectThread(String name){
super.setName(name);
}
@Override
public void run() {
synchronized (u){
System.out.println("in " + getName());
LockSupport.park();
if(Thread.interrupted()){
System.out.println(getName() + " 被中断了" );
}
System.out.println(getName() + "执行结束");
}
}
}
public static void main(String[] args) throws InterruptedException {
//代码片段1
/* t1.start();
Thread.sleep(100);
t2.start();
LockSupport.unpark(t1);
LockSupport.unpark(t2);
t1.join();
t2.join();*/
//代码片段2
t1.start();
Thread.sleep(100);
t2.start();
t1.interrupt();
LockSupport.unpark(t2);
}
}
上述z执行代码片段1输出如下:
in t1
t1执行结束
in t2
t2执行结束
这个例子可以看出,我们无法保证unpark()方法发生在park方法之后,但是这段代码可正常执行。说明unpark方法可发生在park之前。
执行代码片段2会输出:
in t1
t1 被中断了
t1执行结束
in t2
t2执行结束
可以看出LockSupport.park()方法支持中断影响,但该方法不会抛出InterruptedException异常,只是默默返回。并且我们从中断后Thread.interrupted()为true可以知道park方法处理中断也并没有清除中断标识。
参考书籍:《Java高并发程序设计(第2版)》《Java并发编程实战》《Java并发编程的艺术》