Java中執行緒異常結束的解決方法是:先捕捉在執行緒執行過程中所產生的例外;然後當執行緒異常時,會透過呼叫setUncaughtExceptionHandler方法來捕獲異常;最後再解決即可。
【推薦教學:#Java教學##】
##我們在開發工程中經常使用到線程,在線程使用上,我們可能會有這樣的場景:
(1)伴隨這一個業務產生一個比較耗時的任務,而這個業務返回並不需要等待該任務。那我們往往會啟動一個執行緒去完成這個非同步任務。
(2)我們需要一個定時任務例如:定時清除數據,我們會起一個定時執行緒去做該任務。上述問題比較簡單,new一個執行緒然後去做這件事。但是我們常常忽略一個問題,線程異常了怎麼辦?例如耗時任務我們只完成了一半,我們就異常結束了(這裡不考慮事務一致性,我們只考慮一定要將任務完成)。又比如在清資料的時候,資料庫發生斷連。這時候我們會發現線程死掉了,任務終止了,我們需要重啟整個專案把該定時任務起起來。
解決這些問題的關鍵是,如何捕捉執行緒執行過程中產生的例外狀況? 我們查看JDK API我們會發現在Thread中有setUncaughtExceptionHandler方法,讓我們可以在執行緒發生異常時,呼叫該方法。Java中執行緒異常結束的解決方法是:
場景一解決思路:
public class Plan1 { private SimpleTask task = new SimpleTask(); public static void main(String[] args) { Plan1 plan = new Plan1(); plan.start(); } public void start(){ Thread thread = new Thread(task); //thread.setDaemon(true); //注释调 否则看不到输出 thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler(){ @Override public void uncaughtException(Thread t, Throwable e) { System.out.println(e.getMessage()); start(); } }); thread.start(); } class SimpleTask implements Runnable{ private int task = 10; @Override public void run() { String threadName = Thread.currentThread().getName(); System.out.println(threadName+"--"+"启动"); while(task>0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } if(System.currentTimeMillis()%3==0){ throw new RuntimeException("模拟异常"); } System.out.println(threadName+"--"+"执行task"+task); task--; } System.out.println(threadName+"--"+"正常终止"); } } }
結果輸出:
Thread-0--启动 Thread-0--执行task10 Thread-0--执行task9 Thread-0--执行task8 Thread-0--执行task7 模拟异常 Thread-1--启动 Thread-1--执行task6 Thread-1--执行task5 模拟异常 Thread-2--启动 Thread-2--执行task4 Thread-2--执行task3 模拟异常 Thread-3--启动 Thread-3--执行task2 模拟异常 Thread-4--启动 Thread-4--执行task1 Thread-4--正常终止還是場景一我們來看一下線程池的方式,思路是一樣的為什麼要再寫一個單線程的線程池方式呢?
public class Plan3 { private SimpleTask task = new SimpleTask(); private MyFactory factory = new MyFactory(task); public static void main(String[] args) { Plan3 plan = new Plan3(); ExecutorService pool = Executors.newSingleThreadExecutor(plan.factory); pool.execute(plan.task); pool.shutdown(); } class MyFactory implements ThreadFactory{ private SimpleTask task; public MyFactory(SimpleTask task) { super(); this.task = task; } @Override public Thread newThread(Runnable r) { Thread thread = new Thread(r); thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { ExecutorService pool = Executors.newSingleThreadExecutor(new MyFactory(task)); pool.execute(task); pool.shutdown(); } }); return thread; } } class SimpleTask implements Runnable{ private int task = 10; @Override public void run() { String threadName = Thread.currentThread().getName(); System.out.println(threadName+"--"+"启动"); while(task>0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } if(System.currentTimeMillis()%3==0){ throw new RuntimeException("模拟异常"); } System.out.println(threadName+"--"+"执行task"+task); task--; } System.out.println(threadName+"--"+"正常终止"); } } }結果輸出:
Thread-0--启动 Thread-0--执行task10 Thread-0--执行task9 Thread-1--启动 Thread-1--执行task8 Thread-2--启动 Thread-2--执行task7 Thread-2--执行task6 Thread-2--执行task5 Thread-2--执行task4 Thread-2--执行task3 Thread-2--执行task2 Thread-3--启动 Thread-3--执行task1 Thread-3--正常终止由於這邊只是用單線程,所以發現和上面差別不大。不過也展示了線程池是如何捕捉線程異常的。 #########場景二解決方法#########現在我們看看場景二定時任務,為什麼我要寫一份單執行緒池的捕獲異常方式,就是用於和下面做對比。 ######定時任務我們常常用ScheduledExecutorService,和上述ExecutorService取得方式一樣。但是如果我們參照上述方式寫定時任務,然後取得異常。我們會發現我們無法在uncaughtException方法內取得到線程的例外。異常消失了,或者說執行緒發生異常根本就沒呼叫uncaughtException方法。後來查看相關API,發現在ScheduledExecutorService取得異常的方式可以使用ScheduledFuture物件來取得具體方式如下:###
public class Plan2 { private SimpleTask task = new SimpleTask(); public static void main(String[] args) { Plan2 plan = new Plan2(); start(plan.task); } public static void start(SimpleTask task){ ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor(); ScheduledFuture<?> future = pool.scheduleAtFixedRate(task, 0, 1000, TimeUnit.MILLISECONDS); try { future.get(); } catch (InterruptedException | ExecutionException e) { System.out.println(e.getMessage()); start(task); }finally { pool.shutdown(); } } class SimpleTask implements Runnable{ private volatile int count = 0; @Override public void run() { String threadName = Thread.currentThread().getName(); System.out.println(threadName+"--"+"启动"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } if(System.currentTimeMillis()%3==0){ throw new RuntimeException("模拟异常"); } System.out.println(threadName+"--"+"执行task"+count); count++; System.out.println(threadName+"--"+"正常终止"); } } }######結果輸出:######
pool-1-thread-1--启动 java.lang.RuntimeException: 模拟异常 pool-2-thread-1--启动 pool-2-thread-1--执行task0 pool-2-thread-1--正常终止 pool-2-thread-1--启动 pool-2-thread-1--执行task1 pool-2-thread-1--正常终止 pool-2-thread-1--启动 pool-2-thread-1--执行task2 pool-2-thread-1--正常终止 pool-2-thread-1--启动 java.lang.RuntimeException: 模拟异常 pool-3-thread-1--启动 pool-3-thread-1--执行task3 pool-3-thread-1--正常终止 pool-3-thread-1--启动 java.lang.RuntimeException: 模拟异常 pool-4-thread-1--启动 pool-4-thread-1--执行task4 pool-4-thread-1--正常终止 .....###至此我們實作了就算到此我們實作了就算定時任務發生異常,總有一個執行緒會去執行。一個線程倒下,會有後續線程補上。 ###
以上是Java執行緒異常結束怎麼解決的詳細內容。更多資訊請關注PHP中文網其他相關文章!