#### 線程異常處理
* 在run方法上增加異常處理
```
new Thread(() -> {
try {
System.err.println(3 / 2);
System.err.println(3 / 0);
} catch (Exception e) {
System.err.println("Catch exception===>" + e.getMessage());
}
}).start();
```
* 使用UncaughtExceptionHandler處理未捕獲異常
```
Thread thread = new Thread(() -> {
System.err.println(3 / 2);
System.err.println(3 / 0);
});
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.err.println(Thread.currentThread().getName() + "==>" + e.getMessage());
}
});
thread.start();
```
可以為所有的Thread設置一個默認的UncaughtExceptionHandler,通過調用Thread.setDefaultUncaughtExceptionHandler\(Thread.UncaughtExceptionHandler eh\)方法
```
public static void main(String[] args) throws InterruptedException {
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.err.println("全局線程默認異常處理:" + t.getName() + "\n" + e.getMessage());
}
});
new Thread(() -> {
System.err.println(3 / 0);
}).start();
new Thread(() -> {
System.err.println(args[4]);
}).start();
}
```
#### 線程池異常處理
ExecutorService->execute方法線程處理
```
public class ExecuteCaught
{
public static void main(String[] args)
{
ExecutorService exec = Executors.newCachedThreadPool();
Thread thread = new Thread(new Task());
thread.setUncaughtExceptionHandler(new ExceptionHandler());
exec.execute(thread);
exec.shutdown();
}
}
output=====>
1
Exception in thread "pool-1-thread-1" java.lang.ArithmeticException: / by zero
at com.exception.Task.run(NoCaughtThread.java:25)
at java.lang.Thread.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
```
該方式并未捕獲異常,正確的處理方法
```
public class ExecuteCaught
{
public static void main(String[] args)
{
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new ThreadPoolTask());
exec.shutdown();
}
}
class ThreadPoolTask implements Runnable
{
@Override
public void run()
{
Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler());
System.out.println(3/2);
System.out.println(3/0);
System.out.println(3/1);
}
}
```
_注意_
只有通過execute提交的任務,才能將它拋出的異常交給UncaughtExceptionHandler,而通過submit提交的任務,無論是拋出的未檢測異常還是已檢查異常,都將被認為是任務返回狀態的一部分。如果一個由submit提交的任務由于拋出了異常而結束,那么這個異常將被Future.get封裝在ExecutionException中重新拋出
```
public static void main(String[] args) throws InterruptedException {
ExecutorService exec = Executors.newCachedThreadPool();
exec.submit(() -> {
System.err.println(3 / 0);
});
exec.shutdown();
}
### 未捕獲異常
```
正確方式:
```
public static void main(String[] args) throws InterruptedException {
ExecutorService exec = Executors.newCachedThreadPool();
Future<?> future = exec.submit(() -> {
System.err.println(3 / 0);
});
try {
Object o = future.get();
} catch (ExecutionException e) {
System.err.println("捕獲異常:" + e.getMessage());
}
exec.shutdown();
}
```
【知識點】
1. 如果設置了實例屬性uncaughtExceptionHandler(每個線程對象獨有),則調用該處理器對未捕獲異常進行處理;
2. 如果沒有設置未捕獲異常處理器(即1中的uncaughtExceptionHandler),則將線程對象的ThreadGroup當作未捕獲異常處理器,在ThreadGroup中獲取所以線程對象共享的靜態屬性defaultUncaughtExceptionHandler來處理未捕獲異常(前提是靜態的set方法你調用了并且傳入處理器實例\);
3. 如果兩個set方法都沒有調用,那么異常棧信息將被推送到System.err進行處理;
【參考資料】
https://blog.csdn.net/reliveIT/article/details/51167545
- 簡介
- 概述
- 進程vs線程
- 資源限制
- 有關并行的兩個定律
- 線程同步和阻塞
- 線程阻塞
- 線程的特性
- 守護線程
- 線程異常
- Thread
- 線程狀態
- 線程中斷
- wait¬ify
- suspend&resume
- join&yield
- notify¬ifyAll
- Thread.sleep
- 線程任務
- Runnable
- Callable
- Future模式
- FutureTask
- 線程實現方式
- 內核線程實現
- 用戶線程實現
- 混合實現
- Java線程的實現
- java與協程
- 纖程-Fiber
- 線程調度
- 多線程協作方式
- 阻塞
- 放棄
- 休眠
- 連接線程
- 線程估算公式
- 線程活躍性
- 死鎖
- 線程安全性
- 對象的發布與逸出
- 構造方法溢出
- 線程封閉
- 對象的可變性
- 原子性
- 原子操作
- CPU原子操作原理
- 總線鎖
- 緩存鎖
- JAVA如何實現原子操作
- long和double讀寫操作原子性
- Adder和Accumulator
- 線程性能
- 同步工具類
- 閉鎖
- CountDownLatch
- FutureTask
- 信號量
- 柵欄
- CyclicBarrier
- Exchanger
- 并發編程
- volatile
- synchronized
- 無鎖
- 偏向鎖
- 輕量級鎖
- 鎖的優缺點對比
- 鎖升級
- 鎖消除
- Monitor
- synchronized語法
- Mutex Lock
- synchronized實踐問題
- synchronized&ReentrantLock
- Lock
- ReentrantLock
- Condition
- 讀寫鎖
- ReadWriteLock
- StampedLock
- 線程池
- Executor
- ExecutorService
- Executors
- ThreadPoolExecutor
- RejectedExecutionHandler
- ThreadFactory
- 線程池大小公式
- 動態調整線程池大小
- Fork/Join框架
- ForkJoinPool
- CompletableFuture
- JUC并發工具包
- LockSupport
- 延時任務與周期任務
- Timer
- TimerTask
- 異構任務并行化
- CompletionService
- volatile和synchronized比較
- 鎖優化
- 鎖相關概念
- 悲觀鎖(排它鎖)
- 樂觀鎖
- 自旋鎖
- 樂觀鎖vs悲觀鎖
- JVM鎖優化-鎖消除
- ThreadLocal
- InheritableThreadLocal
- TransmittableThreadLocal
- ThreadLocalRandom
- 無鎖
- AtomicInteger
- Unsafe
- AtomicReference
- AtomicStampedReference
- AtomicIntegerArray
- AtomicIntegerFieldUpdater
- 無鎖Vector
- LongAdder
- LongAccumulator
- 常見鎖類型
- 悲觀鎖&獨占鎖
- 樂觀鎖
- 樂觀鎖vs悲觀鎖
- 自旋鎖vs適應性自旋鎖
- 公平鎖vs非公平鎖
- 可重入鎖vs非可重入鎖
- 獨享鎖vs共享鎖
- 互斥鎖
- CAS
- AQS介紹
- AQS深入剖析
- AQS框架
- AQS核心思想
- AQS數據結構
- 同步狀態State
- ReentrantLock vs AQS
- AQS與ReentrantLock的關聯
- ReentrantLock具體實現
- 線程加入等待隊列
- 等待隊列中線程出隊列時機
- 如何解鎖
- 中斷恢復后的執行流程
- ReentrantLock的可重入應用
- JUC中的應用場景
- 自定義同步工具
- CLH鎖
- 并發框架
- Akka
- Disruptor-無鎖緩存框架
- 常見面試題
- 兩個線程交替打印A和B
- 附錄