LockSupport注意事项
目录
前言
原本以为LockSupport的park()方法会直接阻塞线程, 但是在阅读AQS源码的时候, 发现不是这个样子, 所以这里也记录一下LockSupport的park()方法的一些注意事项
LockSupport.park()
- 功能: 阻塞当前线程
- park方法只要线程设置了中断标志位,就直接返回,且不会清除中断标志位.
- 如下两个条件任何一个成立,park()都不会阻塞:
- 中断标志位存在(wait,join,sleep或Thread.interrupted()都会清除中断标志位)
- _counter为1(之前调用了unpark或者interrupt)
- sleep方法响应中断, 会修改标志位, 但是不会修改_counter
- 执行Thread.interrupted()会复位, 并且清空_counter
LockSupport.park() 不阻塞的场景
线程被设置了中断标志位的情况下, park()方法不会阻塞
@Test
public void lockSupport3() throws InterruptedException {
LOGGER.info("start");
Thread thread = new Thread(() -> {
LOGGER.info("thread start");
long start = System.currentTimeMillis();
while ((System.currentTimeMillis() - start) < 3L) {
}
LockSupport.park();
LOGGER.info("thread end");
});
thread.start();
// 中断线程
thread.interrupt();
Thread.sleep(5L);
LOGGER.info("end");
}
通过响应sleep()中断异常, 清除了中断标志位
响应sleep()方法的中断不会更改_counter, 所以park()还是不会阻塞线程
/**
* 响应sleep()方法导致中断标志被清除, 但是LockSupport.park()方法还是不会阻塞
*/
@Test
public void lockSupport() throws InterruptedException {
final String mark = "interrupt state:{}";
Thread thread = new Thread(() -> {
LOGGER.info("i`m start");
LOGGER.info(mark, Thread.currentThread().isInterrupted());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// sleep()方法响应中断会清除标志位, 但是不会更改_counter
LOGGER.info(mark, Thread.currentThread().isInterrupted());
}
LOGGER.info("i`m work");
LockSupport.park();
LOGGER.info(mark, Thread.currentThread().isInterrupted());
LOGGER.info("i`m end");
}, "lockSupport");
thread.start();
thread.interrupt();
Thread.sleep(1000);
LOGGER.info("thread end");
}
在unpark()方法之前执行了park()方法
/**
* 在park之前执行unpark()方法, 线程不会阻塞
*/
@Test
public void lockSupport2() {
LOGGER.info("start");
LockSupport.unpark(Thread.currentThread());
/*不会阻塞*/
LockSupport.park();
LOGGER.info("end");
}