java使用預設線程池踩過的坑(一)

來源:互聯網
上載者:User

標籤:java   task   api   

雲智慧(北京)科技有限公司 陳鑫
情境
一個調度器,兩個調度任務,分別處理兩個目錄下的txt檔案,某個調度任務應對某些複雜問題的時候會持續特別長的時間,甚至有一直阻塞的可能。我們需要一個manager來管理這些task,當這個task的上一次執行時間距離現在超過5個調度周期的時候,就直接停掉這個線程,然後再重啟它,保證兩個目標目錄下沒有待處理的txt檔案堆積。

問題
直接使用java預設的線程池調度task1和task2.由於外部txt的種種不可控原因,導致task2線程阻塞。現象就是task1和線程池調度器都正常運行著,但是task2遲遲沒有動作。
當然,找到具體的阻塞原因並進行針對性解決是很重要的。但是,這種措施很可能並不能完全、徹底、全面的處理好所有未知情況。我們需要保證任務線程或者調度器的健壯性!
方案計劃
線程池調度器並沒有原生的針對被調度線程的業務運行狀態進行監控處理的API。因為task2是阻塞在我們的商務邏輯裡的,所以最好的方式是寫一個TaskManager,所有的任務線程在執行任務前全部到這個TaskManager這裡來註冊自己。這個TaskManager就負責對於每個自己管轄範圍內的task進行即時全程監控!


後面的重點就是如何處理超過5個執行循環的task了。
方案如下:
一旦發現這個task線程,立即中止它,然後再次重啟;
一旦發現這個task線程,直接將整個pool清空並停止,重新放入這兩個task ——【task明確的情況下】;
方案實施
中止後重啟
Task實作類別
classFileTask extends Thread {
private long lastExecTime = 0;
protected long interval = 10000;

public long getLastExecTime() {    returnlastExecTime;}public void setLastExecTime(longlastExecTime) {    this.lastExecTime =lastExecTime;}public long getInterval() {    return interval;}public void setInterval(long interval) {    this.interval = interval;}public File[] getFiles() {    return null;}@Overridepublic void run() {    while(!Thread.currentThread().isInterrupted()) {        lastExecTime = System.currentTimeMillis();       System.out.println(Thread.currentThread().getName() + " is running ->" + new Date());        try {           Thread.sleep(getInterval() * 6 * 1000);        } catch(InterruptedException e) {       Thread.currentThread().interrupt();           e.printStackTrace();    // 當線程池shutdown之後,這裡就會拋出exception了        }    }}

}
TaskManager
public class TaskManager implements Runnable {
private final static Log logger = LogFactory.getLog(TaskManager.class);

public Set<FileTask> runners = newCopyOnWriteArraySet<FileTask>();ExecutorService pool =Executors.newCachedThreadPool();

public voidregisterCodeRunnable(FileTask process) {
runners.add(process);
}

publicTaskManager (Set<FileTask>runners) {    this.runners = runners;}@Overridepublic void run() {    while(!Thread.currentThread().isInterrupted()) {        try {           long current = System.currentTimeMillis();           for (FileTask wrapper : runners) {               if (current - wrapper.getLastExecTime() >wrapper.getInterval()* 5) {                   wrapper.interrupt();                   for (File file : wrapper.getFiles()) {                       file.delete();                   }                wrapper.start();                 }            }        } catch(Exception e1) {           logger.error("Error happens when we trying to interrupt and restart a task");           ExceptionCollector.registerException(e1);        }        try {           Thread.sleep(500);        } catch(InterruptedException e) {        }    }}

}
這段代碼會報錯java.lang.Thread IllegalThreadStateException。為什麼呢?其實這是一個很基礎的問題,您應該不會像我一樣馬虎。查看Thread.start()的注釋, 有這樣一段:
It is never legal to start a thread more thanonce. In particular, a thread may not be restarted once it has completedexecution.

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

java使用預設線程池踩過的坑(一)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.