Java定時線程池停止超時任務


一、背景
題主最近遇到一個問題,本來通過ScheduledExecutorService線程池定時調度一個任務。奈何不知道為啥跑了2個多月,其中一個任務Hang住了,原本定時的任務則出現了問題。

關於定時線程池,好多人認為設置好頻率(比如1Min),它會按照這個間隔按部就班的工作。但是,如果其中一次調度任務卡住的話,不僅這次調度失敗,而且整個線程池也會停在這次調度上。

我們先從一個例子試着復現下問題:

public class pool {
private static class Runner implements Runnable {
@Override
public void run() {
try {
Thread.sleep(10000);
System.out.println(new Date());
} catch (Exception e) {
e.printStackTrace();
}
}
}

public static void main(String[] args) {
ScheduledExecutorService service 
= Executors.newScheduledThreadPool(1);
service.scheduleAtFixedRate(
new Runner(), 0, 1, TimeUnit.SECONDS);
}
}

  


先從Main看,啟動一個定時線程池,每隔1S調度一次Runner。看上去,應該是1S調度一次,但是Runner的實際執行時間為10S,那多久會調度一次?答案是10S。
所以說,這個Runner不管什么原因掛掉了或者Hang住了,那這個定時調度線程池基本就廢了。

二、解決方法
那我們應該怎么解決這個問題?如果說定時線程池有任務調度的超時策略就完美了,很可惜並沒有。
我們想下在並發編程中,哪種方式有超時策略?
對,Future有,那我們可以結合Future,提供一種自動停止超時任務的方式,來解決某個任務Hang住的問題。

我們簡單修改下,把sleep邏輯移動到Callable中,並在Runner中使用Future來控制超時。

public class pool {
private static class Caller implements Callable<Boolean> {
@Override
public Boolean call() {
try {
Thread.sleep(10000);
System.out.println(new Date());
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}

private static class Runner implements Runnable {
@Override
public void run() {
ExecutorService excutor = Executors.newSingleThreadExecutor();
Future<Boolean> future = excutor.submit(new Caller());
try {
future.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
System.out.println("timeout");
} catch (Exception e) {
e.printStackTrace();
} finally {
excutor.shutdownNow(); // 強制終止任務
}
}
}

public static void main(String[] args) {
ScheduledExecutorService service
= Executors.newScheduledThreadPool(1);
service.scheduleAtFixedRate(
new Runner(), 0, 1, TimeUnit.SECONDS);
}
}

  

備注:
- 實現邏輯相當於轉移了,把本來應該調度的任務交給了另外一個Future單線程去執行。因為存在超時邏輯,不會影響原有定時線程池的執行。
- finally是否需要殺死線程池,因人而異。如果不殺死的話,那超時的任務會繼續執行。

題外話:如果你有好的解決方式,歡迎和題主探討。謝謝。


免責聲明!

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



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