关于线程暂停的方法
1.介绍
- Thread.sleep
- 线程进入 TIMED_WAITING
- 另外,该方法会抛出InterruptedException异常,这是受检查异常,调用者必须处理。
- Object.wati()
- 该Object必须是被当前线程持有的锁
- 线程进入WAITING状态
- LockSupport.park()
- 底层也是调用了Unsafe类的park方法
- 调用park方法时,还允许设置一个blocker对象,主要用来给监视工具和诊断工具确定线程受阻塞的原因
- 调用park方法进入休眠后,线程状态为WAITING
2. 实现原理
- LockSupport.park()
LockSupport.park() 的实现原理是通过二元信号量做的阻塞,要注意的是,这个信号量最多只能加到1。我们也可以理解成获取释放许可证的场景。unpark()方法会释放一个许可证,park()方法则是获取许可证,如果当前没有许可证,则进入休眠状态,直到许可证被释放了才被唤醒。无论执行多少次unpark()方法,也最多只会有一个许可证。
- 和wait的不同
park、unpark方法和wait、notify()方法有一些相似的地方。都是休眠,然后唤醒。但是wait、notify方法有一个不好的地方,就是我们在编程的时候必须能保证wait方法比notify方法先执行。如果notify方法比wait方法晚执行的话,就会导致因wait方法进入休眠的线程接收不到唤醒通知的问题。
而park、unpark则不会有这个问题,我们可以先调用unpark方法释放一个许可证,这样后面线程调用park方法时,发现已经许可证了,就可以直接获取许可证而不用进入休眠状态了。
另外,和wait方法不同,执行park进入休眠后并不会释放持有的锁。
- 对中断的处理
park方法不会抛出InterruptedException,但是它也会响应中断。当外部线程对阻塞线程调用interrupt方法时,park阻塞的线程也会立刻返回。
Thread parkThread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("park begin");
//等待获取许可
LockSupport.park();
//输出thread over.true
System.out.println("thread over." + Thread.currentThread().isInterrupted());
}
});
parkThread.start();
Thread.sleep(2000);
// 中断线程
parkThread.interrupt();
System.out.println("main over");
# 输出结果
park begin
main over
thread over.true
说明因park进入休眠的线程收到中断通知后也会立刻返回,并且可以手动通过Thread.currentThread().isInterrupted()获取到中断位
3. 关于java进程的关闭
在linux中,我们通常用kill命令来关闭一个进程。众所周知,kill有-9和-15两种参数,默认是-15。如果是-15参数,系统就发送一个关闭信号给进程,然后等待进程关闭。在这个过程中,目标进程可以释放手中的资源,以及进行一些关闭操作。
正是有了这个概念,我曾经很大一段时间对java进程的关闭流程有所误解。在我原先的理解中,java进程接收到关闭信号后,会逐一给阻塞中的进程发送中断信号,并等待线程处理完。但其实这是错误的。
java进程收到关闭信号后,不会去关心运行中的那些线程是否运行完,也不会给阻塞中的线程发送中断信号。我们只能通过绑定关闭钩子来中断目标线程并等待线程执行完。
java进程在收到关闭信号后,会执行所有绑定了shutdownHook的线程,确保这些绑定的线程都执行完了才真正关闭。因此,我们要释放资源就要在shutdownHook的线程内操作,然后在线程内等待其他释放资源的线程执行完成。
注意,所有绑定了shutdownHook的线程也是并行执行的,不是顺序执行。另外,用-9参数的kill不会等shutdownHook线程执行完就退出。
参考文档:
https://blog.csdn.net/u013332124/article/details/84647915