裸线程的危害
Thread t = new Thread(load);
t.setDaemon(false);
t.start();
创建裸的非守护线程,kill -15 pid 应用停止的时候,线程一直在跑,应用是停止不了的,只能kill -9 pid,因为jvm会发现仍然有非守护线程在运行中,JVM 只有在“所有非守护线程结束”后才会退出。
而创建守护线程也有问题(t.setDaemon(true)),如果里边是重要的业务逻辑,那么有可能没执行完毕就被干掉了,当只剩守护线程时,JVM 会直接退出,不保证守护线程执行完成。
好的实践方式:线程池 + Spring管理
不要直接 new Thread,而应使用线程池,并交由 Spring 管理生命周期比较好的实践方式,如下例子:
@Bean(destroyMethod = "shutdown")
public ScheduledExecutorService myExecutor() {
return Executors.newSingleThreadScheduledExecutor(
r -> new Thread(r, "my-thread")
);
}
myExecutor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
try {
//业务逻辑
} catch (Exception e) {
LOG.error("Error: ", e);
}
}
}, 0, 30, TimeUnit.SECONDS);
对线程池myExecutor添加注解@Bean(destroyMethod = "shutdown"),Spring会在应用停止的时候回调ScheduledExecutorService.shutdown()方法,实现优雅关闭(与之相对的shutdownNow()是立即关闭)
慎用kill -9
- kill -15(SIGTERM): → 触发 JVM shutdown hook ,Spring 开始优雅关闭(Context.close)。 如果有“线程不退出(非守护 + 死循环)”这种情况,JVM 会一直等。
- kill -9(SIGKILL): → 强制终止,不执行 shutdown hook,所有优雅关闭机制失效。