问题:最近在使用 xxl-job 时,执行器使用异步线程处理任务时,发现日志输出存错乱。第一次的日志能够正常打印到对应的log文件中,后面每次都会打印到最开始的日志文件中如下
分析XxlJobHelper 源码:
XxlJobContext 源码 :
XxlJobContext 使用InheritableThreadLocal, InheritableThreadLocal主要用于子线程创建时,需要自动继承父线程的ThreadLocal变量,方便必要信息的进一步传递。 但对于使用线程池等会池化复用线程的执行组件的情况,线程由线程池创建好,并且线程是池化起来反复使用的;这时父子线程关系的ThreadLocal值传递已经没有意义,应用需要的实际上是把 任务提交给线程池时的ThreadLocal值传递到任务执行时。
解决方案:
使用阿里巴巴TransmittableThreadLocal 替换 XxlJobContext 内的 InheritableThreadLocal
-
xxl-job-core pom 文件映入maven 依赖:
<dependency> <groupId>com.alibaba</groupId> <artifactId>transmittable-thread-local</artifactId> <version>2.14.0</version> </dependency>
-
修改XxlJobContext InheritableThreadLocal 为TransmittableThreadLocal
// TransmittableThreadLocal(TTL): // 在使用线程池等会池化复用线程的执行组件情况下,提供ThreadLocal值的传递功能,解决异步执行时上下文传递的问题 // @Link https://github.com/alibaba/transmittable-thread-local private static TransmittableThreadLocal<XxlJobContext> contextHolder = new TransmittableThreadLocal<XxlJobContext>(); // support for child thread of job handler)
-
重新打包编译
客户端使用
-
修改@Async 默认线程池
@Configuration @EnableAsync public class AsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //配置核心线程数 executor.setCorePoolSize(5); //配置最大线程数 executor.setMaxPoolSize(20); //配置队列大小 executor.setQueueCapacity(1000000); //线程池维护线程所允许的空闲时间 executor.setKeepAliveSeconds(30); //配置线程池中的线程的名称前缀 executor.setThreadNamePrefix("Async-Thread-"); //设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean executor.setWaitForTasksToCompleteOnShutdown(true); //设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住 executor.setAwaitTerminationSeconds(60); // rejection-policy:当pool已经达到max size的时候,如何处理新任务 // CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); //执行初始化 executor.initialize(); // 使用TtlExecutors 修饰线程池 return TtlExecutors.getTtlExecutorService(executor.getThreadPoolExecutor()); } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return null; } }
- 修改后日志输出正常