在主線程中開啓異步線程任務時,主線程的信息時無法直接傳遞到子線程中,此時需要通過線程池實現上下文信息的傳遞
案例如下
package com.eno.config.thread;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.concurrent.ListenableFuture;
public class ThreadPoolTaskExecutorWapper extends ThreadPoolTaskExecutor {
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(ThreadPoolTaskExecutorWapper.class);
/**
* 打印線程池信息
* @param prefix
*/
private void showThreadPoolInfo(String prefix) {
ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();
if (null == threadPoolExecutor) {
return;
}
// 線程池最大線程數
int maximumPoolSize = threadPoolExecutor.getMaximumPoolSize();
// 線程池核心線程數
int corePoolSize = threadPoolExecutor.getCorePoolSize();
// 線程池歷史峯值線程數
int largestPoolSize = threadPoolExecutor.getLargestPoolSize();
// 當前線程池中運行的線程總數(包括核心線程和非核心線程)
int poolSize = threadPoolExecutor.getPoolSize();
// 線程池總任務數
// long taskCount = threadPoolExecutor.getTaskCount();
// 活躍任務數量
int activeCount = threadPoolExecutor.getActiveCount();
// 線程池隊列任務數量
int queueSize = threadPoolExecutor.getQueue().size();
logger.debug("線程池名稱:{},{},活躍任務數:{},任務隊列長度:{},線程池歷史峯值線程數:{},線程池中運行的線程總數{},核心線程數:{},線程池最大線程數:{}",
this.getThreadNamePrefix(), prefix, activeCount, queueSize, largestPoolSize, poolSize, corePoolSize,
maximumPoolSize);
}
@Override
public void execute(Runnable task) {
showThreadPoolInfo("Runnable task do execute");
super.execute(task);
}
@Override
public void execute(Runnable task, long startTimeout) {
showThreadPoolInfo("Runnable task with time do execute");
super.execute(task, startTimeout);
}
@Override
public Future<?> submit(Runnable task) {
showThreadPoolInfo("Runnable task do submit");
return super.submit(task);
}
@Override
public <T> Future<T> submit(Callable<T> task) {
showThreadPoolInfo("Callable task do submit");
return super.submit(wrapSubmit(task));
//return super.submit(task);
}
@Override
public ListenableFuture<?> submitListenable(Runnable task) {
showThreadPoolInfo("Runnable task do submitListenable");
return super.submitListenable(task);
}
@Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
showThreadPoolInfo("Callable task do submitListenable");
return super.submitListenable(task);
}
/**
* 線程上下文切換時傳遞任務描述信息
* @param task
* @return
*/
private <T> Callable<T> wrapSubmit(Callable<T> task) {
Map<String, String> context = MDC.getCopyOfContextMap();
return () -> {
T result = null;
// 將父線程的MDC內容傳給子線程
if(MapUtils.isNotEmpty(context) && StringUtils.isNotBlank(context.get("taskName"))) {
MDC.setContextMap(context);
}
try {
result = task.call();
} finally {
try {
MDC.clear();
} catch (Exception e) {
logger.error("clear mdc error {}",e);
}
}
return result;
};
}
}
2.在主線程中設置mdc信息
MDC.put("taskName", "");