MDC 线程池丢失
1、自定义线程池任务继承ThreadPoolTaskExecutor 并重写
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.slf4j.MDC;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
/**
* 装饰ThreadPoolExecutor,将父线程的MDC内容传给子线程
*/
@Slf4j
public class MDCThreadPoolExecutorTask extends ThreadPoolTaskExecutor {
private final static String TRACE_ID = "traceId";
private static final long serialVersionUID = 1L;
@Override
public <T> Future<T> submit(Callable<T> task) {
Map<String, String> context = MDC.getCopyOfContextMap();
return super.submit(() -> {
T result = null;
try {
if (MapUtils.isNotEmpty(context) && !Strings.isNullOrEmpty(context.get(TRACE_ID))) {
MDC.setContextMap(context);
} else {
LogTraceIdAop.setMDC();
}
}catch (Exception e){
}
try {
result = task.call();
} finally {
try {
LogTraceIdAop.clear();
} catch (Exception e) {
log.warn("mdc clear exception.", e);
}
}
return result;
});
}
}
2、使用自定义线程池-springboot
import com.fintell.dp3.common.config.ComConfig;
import com.fintell.dp3.common.log.MDCThreadPoolExecutorTask;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 线程池配置
*/
@Configuration
@EnableAsync
@Slf4j
public class ThreadPoolTaskConfig {
/**
* 默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,
* 当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
* 当队列满了,就继续创建线程,当线程数量大于等于maxPoolSize后,开始使用拒绝策略拒绝
*/
// 核心线程数(默认线程数)
@Value("${thread.corePoolSize:0}")
private int corePoolSize;
// 最大线程数
@Value("${thread.maxPoolSize:100}")
private int maxPoolSize;
// 缓冲队列大小
@Value("${thread.queueCapacity:200}")
private int queueCapacity;
// 允许线程空闲时间(单位:默认为秒)
@Value("${thread.keepAliveTime:10}")
private int keepAliveTime;
/** 线程池名前缀 */
private static final String threadNamePrefix = "AsyncTask-Api-";
/**
* 核心处理逻辑线程池
* 1、查询待加工变量列表
* 2、变量加工
* 3、发送消息队列
*/
@Bean("taskExecutor")
public ThreadPoolTaskExecutor taskExecutor() {
corePoolSize = (corePoolSize == 0 ? ComConfig.getThreads() : corePoolSize);
// 使用自定义线程池
MDCThreadPoolExecutorTask executor = new MDCThreadPoolExecutorTask();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveTime);
executor.setThreadNamePrefix(threadNamePrefix + "core");
log.info("ThreadPoolTaskExecutor - corePoolSize:{}. maxPoolSize:{}. queueCapacity{}. keepAliveTime{}. threadNamePrefix{}.",
corePoolSize, maxPoolSize, queueCapacity, keepAliveTime, threadNamePrefix + "core");
// 线程池对拒绝任务的处理策略
// CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}
MDC多线程丢失
1、自定义线程
import org.slf4j.MDC;
import java.util.Map;
/**
* 装饰器模式装饰Runnable,传递父线程的线程号
*
* @author yangyongjie
* @date 2020/3/9
* @desc
*/
public class MDCRunnable implements Runnable {
private Runnable runnable;
/**
* 保存当前主线程的MDC值
*/
private final Map<String, String> mainMdcMap;
public MDCRunnable(Runnable runnable) {
this.runnable = runnable;
this.mainMdcMap = MDC.getCopyOfContextMap();
}
@Override
public void run() {
// 将父线程的MDC值赋给子线程
for (Map.Entry<String, String> entry : mainMdcMap.entrySet()) {
MDC.put(entry.getKey(), entry.getValue());
}
// 执行被装饰的线程run方法
runnable.run();
// 执行结束移除MDC值
for (Map.Entry<String, String> entry : mainMdcMap.entrySet()) {
MDC.put(entry.getKey(), entry.getValue());
}
}
}
2、使用自定义线程
// 异步线程打印日志,用MDCRunnable装饰Runnable
new Thread(new MDCRunnable(new Runnable() {
@Override
public void run() {
logger.debug("log in other thread");
}
})).start();
// 异步线程池打印日志,用MDCRunnable装饰Runnable
EXECUTOR.execute(new MDCRunnable(new Runnable() {
@Override
public void run() {
logger.debug("log in other thread pool");
}
}));
EXECUTOR.shutdown();
参考文章
https://mp.weixin.qq.com/s/VwKmDCgeIvtnRfGUh-_pfQ
https://blog.youkuaiyun.com/qq_17522211?spm=1000.2115.3001.5343