JAVA優雅停機的實現


    最近在項目中需要寫一個數據轉換引擎服務,每過5分鍾同步一次數據。具體實現是啟動engine server后會初始化一個ScheduledExecutorService和一個ThreadPoolExecutor線程池。schduel executor每過5分鍾將dataTransformList中每一個tranform加入到線程池中運行。每一個數據轉化器負責轉換一組數據庫數據。在執行過程中存在服務重啟並且此時tranform正在轉換數據並且數據沒有全部操作完,此時希望正在執行的work能正常完成作業后再退出。優雅停機在服務重啟,服務關閉顯得比較重要了(盡管不能解決服務器突然斷電導致服務瞬間不可用等原因)。

    普通的優雅停機:當使用kill PID的時候jvm會收到服務停止信號並執行shutdownHook的線程

Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
synchronized (EngineBootstrap.class) {
            EngineServer.getInstance().shutdown();
running = false;
EngineBootstrap.class.notify();
        }
}
});
EngineServer的shutdown方法
public void shutdown() {
    this.transformExecutor.shutdown();
this.scheduledExecutorService.shutdown();
}

ThreadPoolExecutor的shutdown方法會中斷所有的空閑任務,保持正在運行中的任務執行完畢,但是由於kill PID一段時間后jvm就退出了導致正在執行的任務還沒有完成就停止了。

改進后的優雅停機:
Signal sig = new Signal(getOSSignalType());
Signal.handle(sig, new SignalHandler() {
public void handle(Signal signal) {
synchronized (EngineBootstrap.class) {
EngineServer.getInstance().shutdown();
running = false;
EngineBootstrap.class.notify();
}
}
});

private static String getOSSignalType() {
return System.getProperties().getProperty("os.name").
toLowerCase().startsWith("win") ? "INT" : "USR2";
}
linux下通過kill -l查看 31 對應於 SIGUSR2 執行kill -31 PID, SignalHander會接收到signal number為31的信號並執行server shutdown,此時jvm並不會退出直到線程池所有正在執行的線程全部執行完畢才會安全退出。
java -jar data-engine-1.0.0-SNAPSHOT.jar
sh shutdown.sh
可以看到主線程安全退出后,線程池中的work執行完畢后java進程才結束
chenbanghongs-MacBook-Pro:nbugs-data-engine sylar$ java  -jar target/data-engine-1.0.0-SNAPSHOT.jar.zip
1
2
3
4
5
31
優雅停機
主線程安全退出
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
transform

 


下載
data-engine-1.0.0-SNAPSHOT.jar.zip
shutdown.sh




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM