論壇貼吧問題:如何終止執行時間超時的執行緒
阿新 • • 發佈:2018-12-05
因為現在我要監控遠端的一個方法,當這個方法執行超過一段時間時,我就要拋棄這個任務.那個方法我不能修改
測試程式碼:
public class MyThreadPool{ private static MyThreadPool myThreadPool = null; /*** 執行緒的最小數*/ private static int corePoolSize = 5; private static ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, corePoolSize*2,10,TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(corePoolSize),new ThreadPoolExecutor.AbortPolicy()); private MyThreadPool(){} public static MyThreadPool getInstance(){ if(null == myThreadPool){ System.out.println("MyThreadPool is creating!"); myThreadPool = new MyThreadPool(); } return myThreadPool; } /** * 執行任務 */ public void exeWork(final MyWork work,int availableTime){ FutureTask<Boolean> future = new FutureTask<Boolean>(new Callable<Boolean>(){ public Boolean call(){ return work.doSometing(); } }); executor.execute(future); try{ future.get(availableTime, TimeUnit.SECONDS); }catch(ExecutionException e1){ e1.printStackTrace(); }catch(InterruptedException e2){ e2.printStackTrace(); }catch(TimeoutException e3){ System.out.println("執行任務超時!"); }finally{ future.cancel(true); closeExecutor(); } } public void closeExecutor(){ if(executor != null && executor.getActiveCount() ==0 && executor.getQueue().isEmpty()){ executor.shutdown(); } } public static int getCorePoolSize() { return corePoolSize; } public static void setCorePoolSize(int corePoolSize) { MyThreadPool.corePoolSize = corePoolSize; } }
Main 方法
public static void main(String[] args){ MyThreadPool threadPool = MyThreadPool.getInstance(); int availableTime = 5; MyWork b = new BWork(); threadPool.exeWork(b, availableTime);
public class BWork implements MyWork{ public boolean doSometing(){ System.out.println("B starting..."); //模擬遠端的方法 最壞的情況是死迴圈 while(true){ } } }
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
回答:
1 worker 最好以以下的形式進行迴圈
while (true) { if (Thread.currentThread().isInterrupted()) { return; } // do something // thread sleep }
這樣打斷該執行緒,以便結束該執行緒的生命週期。
其實executor.shutdown和shutdownnow也是呼叫thread.interupte來結束執行緒池的生命週期的
// shutdownnow for (Worker w : workers) { w.interruptNow(); } // shutdown for (Worker w : workers) { w.interruptIfIdle(); }
2 其實最簡單的方法是設定所建立的thread為守護執行緒就可以了。
thread factory 生成thread的時候設定t.setDaemon(true);
// t.setDaemon(true); private static ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, corePoolSize * 2, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(corePoolSize), new ThreadFactory() { public Thread newThread(Runnable r) { // TODO Auto-generated method stub final Thread t = new Thread(r); t.setDaemon(true); threads.add(t); return t; } }, new ThreadPoolExecutor.AbortPolicy());
以下是全部程式碼
package test.thread.csdn; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class InterupteThreadTest { private static InterupteThreadTest myThreadPool = null; private static int corePoolSize = 5; private static final List<Thread> threads = new ArrayList<Thread>(); private static ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, corePoolSize * 2, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(corePoolSize), new ThreadFactory() { public Thread newThread(Runnable r) { // TODO Auto-generated method stub final Thread t = new Thread(r); t.setDaemon(true); threads.add(t); return t; } }, new ThreadPoolExecutor.AbortPolicy()); private InterupteThreadTest() { } public static InterupteThreadTest getInstance() { if (null == myThreadPool) { System.out.println("MyThreadPool is creating!"); myThreadPool = new InterupteThreadTest(); } return myThreadPool; } /** * exeWork */ public void exeWork(int availableTime) { FutureTask<Boolean> future = new FutureTask<Boolean>( new Callable<Boolean>() { public Boolean call() { // dead loop mock while (true) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }); executor.execute(future); try { System.out.println(future.get(availableTime, TimeUnit.SECONDS)); } catch (ExecutionException e1) { e1.printStackTrace(); } catch (InterruptedException e2) { e2.printStackTrace(); } catch (TimeoutException e3) { System.out.println("timeout!"); } } public void shut() { executor.shutdown(); } /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { final InterupteThreadTest instance = InterupteThreadTest.getInstance(); instance.exeWork(4); instance.shut(); } }
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
回覆:
1 worker 最好以以下的形式進行迴圈
while (true) { if (Thread.currentThread().isInterrupted()) { return; } // do something }
首先感謝你的回帖,但是有幾點前提我需要澄清:
首先 我為什麼把 work.doSomething() 抽象來 就是因為 那是我即將呼叫別人的方法,我沒辦法改,我要做的就是判斷 doSomething 這個方法是否已經超時,如果超了 那就結束(或丟擲)這個執行緒。
另外main 方法不應該提供對操作池的操作 因為是開放給其他人用的。
還有 我在網上找了幾天資料,說執行緒 是沒辦法被 kill 的 那 tomcat又是如何做到丟擲超時連線的呢?