眾所周知,通過唯一的鏈路id來追蹤一次請求的所有日誌,對於排查生產問題來說,會是非常給力的。這個比較容易實現。我之前的博客也有多次提及。那麼,如果涉及到非同步線程處理的話,我們知道,由於非同步線程與工作線程是兩個不同的線程,因此,這時的線程名會發生變化。一次請求的完整日誌就無法通過唯一的標識來過濾了。 ...
眾所周知,通過唯一的鏈路id來追蹤一次請求的所有日誌,對於排查生產問題來說,會是非常給力的。
這個比較容易實現。我之前的博客也有多次提及。
那麼,如果涉及到非同步線程處理的話,我們知道,由於非同步線程與工作線程是兩個不同的線程,因此,這時的線程名會發生變化。一次請求的完整日誌就無法通過唯一的標識來過濾了。
有沒有辦法呢?
問題即答案。當然是有的。
線程是用來執行任務的,任務是一段程式代碼的封裝。在java中,任務通過 java.lang.Runnable 來表示。使用方面,我們可以自己定義一個實現Runnable的任務類,也可以用lambda表達式的方式直接使用Runnable,來作為線程或線程池的參數。
自定義實現了Runnable的類來使用非同步線程,先貼demo代碼。
實現了Runnable介面的類--MyTask:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.emaxcard.test; import lombok.extern.slf4j.Slf4j; @Slf4j public class MyTask implements Runnable { String flag; public MyTask(String flag) { this.flag = flag; } @Override public void run() { log.info("這是非同步線程里的日誌。參數flag={}", flag); } }View Code
主線程測試類:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.emaxcard.test; import lombok.extern.slf4j.Slf4j; @Slf4j public class RunnableTest { public static void main(String[] args) { log.info("主線程begin"); new Thread(new MyTask("參數值test")).start(); log.info("主線程end"); } }View Code
列印出來的log如下:
16:11:27.613 [main] INFO com.emaxcard.test.RunnableTest - 主線程begin
16:11:27.629 [main] INFO com.emaxcard.test.RunnableTest - 主線程end
16:11:27.630 [Thread-0] INFO com.emaxcard.test.MyTask - 這是非同步線程里的日誌。參數flag=參數值test
我們希望看到的日誌是:
16:11:27.613 [main] INFO com.emaxcard.test.RunnableTest - 主線程begin
16:11:27.629 [main] INFO com.emaxcard.test.RunnableTest - 主線程end
16:11:27.630 [main] INFO com.emaxcard.test.MyTask - 這是非同步線程里的日誌。參數flag=參數值test
小支一招,輕鬆搞定。給 MyTask 加點料,代碼如下。這樣就能實現?是的,因為構造MyTask對象的操作發生在當前工作線程,也就是說,MyTask構造器的代碼是在工作線程里執行的。沒錯,正是基於這一點。
package com.emaxcard.test; import lombok.extern.slf4j.Slf4j; @Slf4j public class MyTask implements Runnable { String flag; String threadName; public MyTask(String flag) { this.flag = flag; this.threadName = Thread.currentThread().getName(); } @Override public void run() { Thread.currentThread().setName(threadName); log.info("這是非同步線程里的日誌。參數flag={}", flag); } }
同樣,用lambda表達式使用Runnable來使用非同步線程,傳遞線程名,也很簡單。貼出來上面的 RunnableTest 的代碼。
package com.emaxcard.test; import lombok.extern.slf4j.Slf4j; @Slf4j public class RunnableTest { public static void main(String[] args) { log.info("主線程begin"); String name = Thread.currentThread().getName(); new Thread(new Runnable() { @Override public void run() { Thread.currentThread().setName(name); log.info("這是非同步線程里的日誌"); } }).start(); log.info("主線程end"); } }
當看到一些不好的代碼時,會發現我還算優秀;當看到優秀的代碼時,也才意識到持續學習的重要!--buguge
本文來自博客園,轉載請註明原文鏈接:https://www.cnblogs.com/buguge/p/16616927.html