众所周知,通过唯一的链路id来追踪一次请求的所有日志,对于排查生产问题来说,会是非常给力的。
这个比较容易实现。我之前的博客也有多次提及。
那么,如果涉及到异步线程处理的话,我们知道,由于异步线程与工作线程是两个不同的线程,因此,这时的线程名会发生变化。一次请求的完整日志就无法通过唯一的标识来过滤了。

有没有办法呢?
问题即答案。当然是有的。

线程是用来执行任务的,任务是一段程序代码的封装。在java中,任务通过 java.lang.Runnable 来表示。使用方面,我们可以自己定义一个实现Runnable的任务类,也可以用lambda表达式的方式直接使用Runnable,来作为线程或线程池的参数。

自定义实现了Runnable的类来使用异步线程,先贴demo代码。

实现了Runnable接口的类–MyTask:

package com.emaxcard.test;import lombok.extern.slf4j.Slf4j;@Slf4jpublic class MyTask implements Runnable {    String flag;    public MyTask(String flag) {        this.flag = flag;    }    @Override    public void run() {        log.info("这是异步线程里的日志。参数flag={}", flag);    }}

View Code

主线程测试类:

package com.emaxcard.test;import lombok.extern.slf4j.Slf4j;@Slf4jpublic 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;@Slf4jpublic 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;@Slf4jpublic 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


hr.signhr{width:80%;margin:0 auto;border: 0;height: 4px;background-image: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0))}