一 . 前言
有一个后台服务,有个时候需要停下服务,关闭的时候需要“优雅”的关闭,保证程序是正常结束的。
二 . Signal Handing 处理
1. 案例说明: 有三个线程Level1 、 Level2 、 Level3 ,关闭时候需要保证顺序 Level1 结束 -> Level2结束 -> Level3结束
2.案例代码:
package demo;
import sun.misc.Signal;
import sun.misc.SignalHandler;
import java.util.concurrent.atomic.AtomicBoolean;
public class Graceclose implements SignalHandler {
private static AtomicBoolean isLevel1Stop = new AtomicBoolean(false);
private static AtomicBoolean isLevel2Stop = new AtomicBoolean(false);
private static AtomicBoolean isLevel3Stop = new AtomicBoolean(false);
public void level1(){
try{
while (true && !isLevel1Stop.get()){
System.out.println("level1 is running");
Thread.sleep(1000);
}
}catch(Exception e ){
e.printStackTrace();
}finally{
isLevel2Stop.set(true);
//close resource
System.out.println("level1 close the resource");
}
}
private class Level2 implements Runnable{
@Override
public void run() {
try{
while(true && !isLevel2Stop.get()){
System.out.println("leve2 is running");
Thread.sleep(1000);
}
}catch(Exception e ){
exceptionClose();
e.printStackTrace();
}finally {
//close resource
System.out.println("level2 close the resource");
}
}
}
private class Level3 implements Runnable{
@Override
public void run() {
try{
while(true && !isLevel3Stop.get()){
System.out.println("leve3 is running");
Thread.sleep(1000);
}
}catch(Exception e ){
exceptionClose();
e.printStackTrace();
}finally {
//close resource
System.out.println("level3 close the resource");
}
}
}
private void exceptionClose(){
isLevel1Stop.set(true);
}
public void start() throws Exception {
Thread level2Thr = new Thread(new Level2());
level2Thr.start();
Thread level3Thr = new Thread(new Level3());
level3Thr.start();
level1();
level2Thr.join();
// 表明level2Thr 已经执行完,设置isLevel3Stop = true
isLevel3Stop.set(true);
level3Thr.join();
}
@Override
public void handle(Signal signal) {
System.out.println("SignalHandler.handle is called");
isLevel1Stop.set(true);
}
public static void main(String[] args) throws Exception{
Graceclose task = new Graceclose();
Signal.handle(new Signal("TERM"), task);
task.start();
System.out.println("the main has finished");
}
}
上述中的level1 level2 level3 在程序结束时会保证顺序关闭(引入了 原子变量 AtomicBoolean 判断是否停止运行),当然如果Leve3 程序抛出异常也提前关闭
三. 注意事项
1. Signal.handle(new Signal("TERM"),task) 需要在main开始的时候就进行注册
2. Singal 在执行 kill -15/term 的时候,对main函数不会有什么影响。 但是Runtime.getRuntime().addShutdownHook 方法在接受到 kill 15/term 信号时main 函数已经执行完(即jvm关闭的时候会执行设置的所有的 addShutdownHook方法)