这是我参与11月更文挑战的第22天,活动详情查看:2021最后一次更文挑战
JDK中的rt.jar包中的LockSupport是个工具类,它的主要作用是挂起和唤醒线程,该工具类是创建锁和其他同步类的基础。
LockSupport类与每个使用它的线程都会关联一个许可证,在默认情况下调用LockSupport类的方法的线程是不持有许可证的。LockSupport是使用Unsafe类实现,下面介绍LockSupport中的几个函数。
1.void park()方法
如果调用park方法的线程已经拿到了与LockSupport关联的许可证,则调用LockSupport关联的许可证,则调用LockSupport.park()时,会立即返回,否则调用线程会被禁止参与线程的调度,也就是被阻塞挂起。
public static void main(String[] args) {
System.out.println("begin park");
LockSupport.park();
System.out.println("end park");
}
复制代码
在其他线程调用unpark()方法并且将当前线程作为参数时,调用park方法而被阻塞的线程会返回。另外如果其他线程调用了阻塞线程的interrupt()方法,设置了中断标志或者线程被虚假唤醒,则阻塞线程也会返回。所以在调用park方法时,最好使用循环条件判断方式。因调用park()方法而被阻塞的线程被其他线程中断而返回时并不会抛出InterruptedException异常。
- void unpark(Thread thread)方法
当一个线程调用unpark时,如果参数thread线程没有持有thread与LockSupport类关联的许可证,则让thread线程持有。如果thread之前因调用park()而被挂起,则调用unpark后,则该线程会被唤醒。如果thread之前没有调用park,则调用unpark方法后,再调用park方法,其会立即返回。
public static void main(String[] args) throws InterruptedException{
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("child thread begin park!");
LockSupport.park();
System.out.println("child thread unpark!");
}
});
Thread.sleep(1000);
System.out.println("main thread begin unpark!");
LockSupport.unpark(thread);
}
复制代码
park方法返回时不会告诉你因何种原因返回,所以调用者需要根据之前调用park方法的原因,再次检查条件是否满足,如果不满足还需要再次调用park方法。 例如,根据调用park方法后的线程被中断后返回,我们修改上面的例子代码,删除LockSupport.Unpark(thread);然后添加thread.interrupt()。
public static void main(String[] args) throws InterruptedException{
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("child thread begin park!");
while (!Thread.currentThread().isInterrupted()) {
LockSupport.park();
}
System.out.println("child thread unpark!");
}
});
Thread.sleep(1000);
System.out.println("main thread begin unpark!");
thread.interrupt();
}
复制代码
在如上代码中,只用中断子线程,子线程才会运行结束,如果子线程不被中断,即使调用unpark方法,子线程也不用结束。
- void parkNanos(long nanos)方法
与park方法类似,只不过是当调用park被挂起namos时间后,会自动返回。
- park (Object blocker)
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);
setBlocker(t, null);
}
复制代码
park方法还支持带有blocker参数的方法,当线程在没有持有许可证的情况下调用park方法而被阻塞挂起时候,这个blocker对象会被记录到该线程内部。