1. API
- LockSupport.park():暂停当前线程
- LockSupport.unpark (线程对象):恢复某个线程的运行
1.1 先 park 再 unpark
main 线程睡眠时间大于 t1 线程睡眠时间
@Slf4j(topic = "c.Test01")
public class Test01 {
public static void main(String[] args) throws Exception {
Thread t1 = new Thread(() -> {
log.info("start...");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("park...");
LockSupport.park();
log.info("resume...");
}, "t1");
t1.start();
TimeUnit.SECONDS.sleep(2);
log.info("unpark... ");
LockSupport.unpark(t1);
}
}
通过运行结果得出结论:阻塞的线程在执行 unpark 方法后,恢复运行
1.2 先 unpark 再 park
main 线程睡眠时间小于 t1 线程睡眠时间
@Slf4j(topic = "c.Test01")
public class Test01 {
public static void main(String[] args) throws Exception {
Thread t1 = new Thread(() -> {
log.info("start...");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("park...");
LockSupport.park();
log.info("resume...");
}, "t1");
t1.start();
TimeUnit.SECONDS.sleep(1);
log.info("unpark... ");
LockSupport.unpark(t1);
}
}
通过运行结果得出结论:如果 t1 线程在执行 park 方法之前执行了 unpark 方法,park 方法不能让 t1 线程进入阻塞状态
1.3 执行多次 unpark 再 park
@Slf4j(topic = "c.Test02")
public class Test02 {
public static void main(String[] args) throws Exception {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
Thread t1 = new Thread(() -> {
log.info("start...");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("park1...");
LockSupport.park();
log.info("park2...");
LockSupport.park();
log.info("resume...");
}, "t1");
t1.start();
TimeUnit.SECONDS.sleep(1);
log.info("unpark : " + LocalDateTime.now().format(dateTimeFormatter));
LockSupport.unpark(t1);
log.info("unpark : " + LocalDateTime.now().format(dateTimeFormatter));
LockSupport.unpark(t1);
TimeUnit.SECONDS.sleep(3);
log.info("unpark : " + LocalDateTime.now().format(dateTimeFormatter));
LockSupport.unpark(t1);
}
}
通过运行结果得出结论:如果 t1 线程在执行 park 方法之前执行了多次 unpark 方法,第一次执行 park 方法不进入阻塞状态,再一次执行 park 方法将进入阻塞状态
1.4 小结
- 如果一个运行的线程在执行 park 方法之前,未执行 unpark 方法,线程进入阻塞状态
- 如果一个运行的线程在执行 park 方法之前,执行了一次或多次 unpark 方法,线程不进入阻塞状态,而是继续向下运行
2. park & unpark 与 wait & notify & notifyAll 的区别
- wait & notify & notifyAll 需要和 synchronized 关键字一起使用,而 park & unpark 不需要
- park & unpark 会阻塞(唤醒 )指定线程,而 notify 只能随机唤醒一个等待线程,notifyAll 唤醒所有等待线程
- park & unpark 可以先 unpark 再 park,给线程一次 “免阻塞” 的机会,而 wait & notify & notifyAll 不可以