如何解决异步线程导致的traceId为空的问题
作者:从int开始
文章讨论了在使用异步线程时,traceId为空的问题,并提出了使用线程池的解决方案,作者分享了个人经验,并鼓励大家参考和支持脚本之家
异步线程导致的traceId为空问题
1. 使用线程池
import lombok.Data; import org.slf4j.MDC; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * xxx任务线程池配置 */ @Configuration @ConfigurationProperties(prefix = "thread-pool.x-xx") @Data public class XxxThreadPoolConfiguration { /** * Minimum number of threads to keep alive */ private int corePoolSize = 8; /** * Maximum number of threads in the pool */ private int maxPoolSize = 16; /** * Time in seconds to keep excess idle threads alive */ private long keepAliveTime = 60; /** * queue size */ private int queueSize = 1000; @Bean("xXxExecutor") public ThreadPoolExecutor xXxExecutor() { ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS, new LinkedBlockingQueue<>(queueSize)); executor.setThreadFactory(runnable -> { Thread thread = new Thread(runnable); thread.setName("commonExecutor-" + thread.getId()); return thread; }); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); return executor; } public static class MdcThreadPoolExecutor extends ThreadPoolExecutor { public MdcThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); } @Override protected void beforeExecute(Thread t, Runnable r) { // 在任务执行前,从当前线程(如果是主线程调用的话,就是主线程的MDC)获取traceId并设置到即将执行任务的线程的MDC中 String traceId = MDC.get("traceId"); MDC.put("traceId", traceId); super.beforeExecute(t, r); } @Override protected void afterExecute(Runnable r, Throwable t) { // 任务执行后清除MDC中的traceId(避免内存泄漏等问题,释放资源) MDC.remove("traceId"); super.afterExecute(r, t); } } }
2. 使用
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; @Service public class XxxController{ // 构造器注入 public OutChargeOrderPushController( @Qualifier("xXxExecutor")ThreadPoolExecutor executor ) { this.executor = executor; } // 使用异步操作方法的时候把executor 传进去即可 }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。