如何解决异步线程导致的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 传进去即可
}
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
