JAVA異常和日誌
未捕獲異常
Runnable 未捕獲異常
@Slf4j
public class RunnableDemo implements Runnable{
boolean flag;
public RunnableDemo(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
log.info("進入runnableDemo");
if(flag){
throw new NumberFormatException("RunnableDemo測試異常");
}
log.info("進入runnableDemo 結束");
}
}
以下日誌列印在控制,不列印在日誌檔案中
10:09:17.110 [Thread-0] INFO c.z.d.exception.utils.RunnableDemo - 進入runnableDemo
Exception in thread "Thread-0" java.lang.NumberFormatException: RunnableDemo測試異常
at com.zhou.demo.exception.utils.RunnableDemo.run(RunnableDemo.java:29)
at java.lang.Thread.run(Thread.java:745)
因為其實執行的是 java.lang.ThreadGroup#uncaughtException;輸出日誌是System.err.print,所以不會輸出到日誌檔案。
執行緒池未捕獲異常
執行緒池會捕獲任務丟擲的異常和錯誤,處理策略會受到我們提交任務的方式而不同。
pool.execute
public static void testThreadPoolExec(Boolean flag){
ExecutorService executorService = Executors.newFixedThreadPool(1);
Thread thread = new Thread(new RunnableDemo(flag));
executorService.execute(thread);
}
只有通過execute提交的任務,才能將它丟擲的異常交給UncaughtExceptionHandler
實際也是執行 java.lang.ThreadGroup#uncaughtException
效果類似,列印在控制檯不列印在日誌檔案
pool.submit
public static void testThreadPoolSumbit(Boolean flag){
ExecutorService executorService = Executors.newFixedThreadPool(1);
Thread thread = new Thread(new RunnableDemo(flag));
//TODO 沒有以下,錯誤日誌不會列印到控制檯 e.printStackTrace()不會列印到logback日誌 列印到日誌使用log.error
Future<?> submit = executorService.submit(thread);
try {
submit.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
而通過submit提交的任務,submit()方式提交的任務會返給我們一個Future,無論是丟擲的未檢測異常還是已檢查異常,都將被認為是任務返回狀態的一部分。如果一個由submit提交的任務由於丟擲了異常而結束,那麼這個異常將被Future.get封裝在ExecutionException中重新丟擲。
UncaughtExceptionHandler
實現Thread的UncaughtExceptionHandler介面
@Slf4j
public class MyExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
log.error("Exception in thread {}", t.getName(), e);
}
}
###執行緒
Thread.setUncaughtExceptionHandler(UncaughtExceptionHandler)
//設定全域性的預設異常處理機制
Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler)
除了執行緒池的sumbit方法,其他都按照MyExceptionHandler的log error列印到日誌中了。
@Slf4j
public class RunnableHnadlerDemo implements Runnable{
boolean flag;
public RunnableHnadlerDemo(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
log.info("進入runnableDemo");
if(flag){
throw new NumberFormatException("RunnableDemo測試異常");
}
log.info("進入runnableDemo 結束");
}
public static void testRunnable(Boolean flag){
Thread thread = new Thread(new RunnableDemo(flag));
thread.start();
}
public static void testThreadPoolExec(Boolean flag){
ExecutorService executorService = Executors.newFixedThreadPool(1);
Thread thread = new Thread(new RunnableDemo(flag));
executorService.execute(thread);
}
public static void lambadThread(){
Thread thread = new Thread(() -> {
log.info("進入 lambadThread");
if (true) {
throw new NumberFormatException("lambadThread測試異常");
}
log.info("進入lambadThread 結束");
});
thread.start();
}
public static void testThreadPoolSumbit(Boolean flag){
ExecutorService executorService = Executors.newFixedThreadPool(1);
Thread thread = new Thread(new RunnableDemo(flag));
Future<?> submit = executorService.submit(thread);
}
public static void main(String[] args) {
Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler());
//testRunnable(true);
//testThreadPoolExec(true);
//lambadThread();
testThreadPoolSumbit(true);
}
### 執行緒池
執行緒池的UncaughtExceptionHandler我們需要一個個設定,藉助工具Apache Commons 和 Google Guava,可以實現,參考。
結論:
執行緒中未捕獲異常不會出現的日誌檔案!!!
執行緒池中sumbit提交的任務,異常封裝在ExecutionException,不判斷結果類方法不會輸出異常!!!
所以一定要注意對執行緒中異常的處理,不然任務可能失敗的毫無聲息。
使用CompletableFuture時候,使用handle或者exceptionally;以便以處理有可能的異常
## handle 異常返回handle的值,正常會返回正常值
### 當執行時出現了異常,可以通過exceptionally進行補償
public static void testFutureR(Boolean flag){
CompletableFuture.runAsync(() -> {
log.info("進入CompletableFuture");
if (flag) {
throw new RuntimeException("測試非同步異常");
}
log.info("進入CompletableFuture結束");
}).whenComplete((r, e) ->{
if(e != null){
log.error("執行未完成出現異常", e);
}
}).exceptionally(e -> {
log.error("exceptionally出現異常", e);
return null;
}).handle((t, e) -> {
log.error("hander 處理異常", e);
return null;
}).join();
}
日誌記錄和nohup
Linux的3種重定向 0:表示標準輸入 1:標準輸出,在一般使用時,預設的是標準輸出 2:標準錯誤資訊輸出
可以使用nohup執行命令,將日誌輸出到檔案,但是這樣缺乏日誌框架對日誌的細緻處理,控制單個日誌的大小和控制總體的日誌數量;
nohup產生的日誌檔案常常會太大佔滿磁碟或者不方便開啟
nohup java -jar XX.jar> console.out 2>&1 &
方法1 安裝cronolog切割日誌
方法2 命令列切割日誌,然後清空日誌
cat /dev/null > nohup.out
方法3 不重定向,輸出logBack日誌檔案,問題 未捕獲異常
## 什麼日誌也不要
nohup java -jar XX.jar> /dev/null 2>&1 &
方法4 只輸出錯誤日誌到nohup日誌檔案
nohup java -jar XX.jar >/dev/null 2>log &
問題: 錯誤日誌和正常日誌對不上,不方便排查問題
綜上,可以考慮強制對異常進行處理,一勞永逸 。
相關文章
- Java-異常、斷言和日誌Java
- Java核心技術筆記 異常、斷言和日誌Java筆記
- Flutter異常捕獲和Crash崩潰日誌收集Flutter
- OneAPM大講堂 | Java 異常日誌記錄最佳實踐Java
- 前端異常日誌監控 – 使用Sentry前端
- 體面編碼之異常日誌和測試處理
- 在日誌中記錄Java異常資訊的正確姿勢Java
- 《Java核心技術(卷1)》筆記:第7章 異常、斷言和日誌Java筆記
- python自動化測試之異常及日誌Python
- 獲取異常資訊裡再出異常就找不到日誌了,我TM人傻了
- Apiclude中Talkingdata模組異常日誌不能收集問題API
- 【java】異常Java
- java 異常Java
- Java 異常Java
- Java異常Java
- 異常JavaJava
- Java 異常(二) 自定義異常Java
- Java 異常處理:使用和思考Java
- 異常和異常呼叫鏈
- win10 異常關機檢視方法 win10 異常關機日誌怎麼看Win10
- go fiber: 把異常資訊寫到錯誤日誌中Go
- 深度模型的日誌異常檢測,還有誰不會?模型
- 使用log4j列印異常堆疊到日誌檔案
- python 使用 loguru 輸出異常日誌同時列印變數值Python變數
- jmu-Java-06異常-01-常見異常Java
- Java 異常表與異常處理原理Java
- 日誌分析常規操作
- Java異常十一:使用throw丟擲異常物件;throw和throws的區別Java物件
- python監控伺服器應用日誌,推送釘釘機器人,實時關注日誌異常Python伺服器應用日誌機器人
- 異常-異常的概述和分類
- Java 異常(一) 異常概述及其架構Java架構
- Java 異常進階Java
- Java 筆記《異常》Java筆記
- 如何善用Java異常Java
- Java異常機制Java
- Java基礎-異常Java
- JAVA 異常處理Java
- Java自定義異常Java