1. 介绍
1.1. LockSupport类介绍
LockSupport类可以阻塞当前线程以及唤醒指定被阻塞的线程。主要是通过park()和unpark(thread)方法来实现阻塞和唤醒线程的操作的。
每个线程都有一个许可(permit),permit只有两个值1和0,默认是0。
- 当调用unpark(thread)方法,就会将thread线程的许可permit设置成1(注意多次调用unpark方法,不会累加,permit值还是1)。
- 当调用park()方法,如果当前线程的permit是1,那么将permit设置为0,并立即返回。如果当前线程的permit是0,那么当前线程就会阻塞,直到别的线程将当前线程的permit设置为1时,park方法会被唤醒,然后会将permit再次设置为0,并返回。如果调用unpark方法或者当前线程被中断,从能从park()方法中返回
注意:因为permit默认是0,所以一开始调用park()方法,线程必定会被阻塞。调用unpark(thread)方法后,会自动唤醒thread线程,即park方法立即返回。
LockSupport.park方法让线程等待之后,唤醒方式有2种:
- 调用LockSupport.unpark方法
- 调用等待线程的 interrupt()方法,给等待的线程发送中断信号,可以唤醒线程
1.2. 线程等待和唤醒方式
- Object中的wait、notify、notifyAll方法
- juc中Condition接口提供的await、signal、signalAll方法
- juc中的LockSupport提供的park、unpark方法
关于Object和Condtion中线程等待和唤醒的局限性是:线程需要先获取锁;唤醒方法需要在等待方法之后调用,线程才能够被唤醒
1.3. 线程等待和唤醒方式对比
对比点 | Object | Condtion | LockSupport |
前置条件 | 需要在synchronized中运行 | 需要先获取Lock的锁 | 无 |
无限等待 | 支持 | 支持 | 支持 |
超时等待 | 支持 | 支持 | 支持 |
等待到将来某个时间返回 | 不支持 | 支持 | 支持 |
等待状态中释放锁 | 会释放 | 会释放 | 不会释放 |
唤醒方法先于等待方法执行,能否唤醒线程 | 否 | 否 | 可以 |
是否能响应线程中断 | 是 | 是 | 是 |
线程中断是否会清除中断标志 | 是 | 是 | 否 |
是否支持等待状态中不响应中断 | 不支持 | 支持 | 不支持 |
2. 代码示例
LockSupport.park(new BlockerDemo());此方法的参数blocker主要是排查问题使用的。这个参数会在线程堆栈信息中打印出来,方便排查问题,其他暂无他用
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
@Slf4j
public class LockSupportTest {
static class BlockerDemo {
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
log.info(System.currentTimeMillis() + "," + Thread.currentThread().getName() + " start!");
LockSupport.park();
log.info(System.currentTimeMillis() + "," + Thread.currentThread().getName() + " 被唤醒!");
},"线程1");
t1.start();
Thread t2 = new Thread(() -> {
log.info(System.currentTimeMillis() + "," + Thread.currentThread().getName() + " start!");
LockSupport.park(new BlockerDemo());
log.info(System.currentTimeMillis() + "," + Thread.currentThread().getName() + " 被唤醒!");
},"线程2");
t2.start();
TimeUnit.SECONDS.sleep(5);
LockSupport.unpark(t1);
LockSupport.unpark(t2);
}
}
参考
https://cloud.tencent.com/developer/article/1551323