springboot 線程池 異步線程上下文切換及信息傳遞

在主線程中開啓異步線程任務時,主線程的信息時無法直接傳遞到子線程中,此時需要通過線程池實現上下文信息的傳遞

案例如下

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", "");

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章