xuxueli / xxl-job

A distributed task scheduling framework.(分布式任务调度平台XXL-JOB)
http://www.xuxueli.com/xxl-job/
GNU General Public License v3.0
27.38k stars 10.83k forks source link

2.3.0多线程日志打印混乱 #2925

Open maiqijiadeershaoye opened 2 years ago

maiqijiadeershaoye commented 2 years ago

Please answer some questions before submitting your issue. Thanks!

Which version of XXL-JOB do you using?

2.3.0

Expected behavior

   采用线程池时,在子线程中打印日志时,第一次的日志能够正常打印到对应的log文件中,后面每次都会打印到最开始的日志文件中,这个是因为父子线程导致的,什么时候修复下呢。

Actual behavior

Steps to reproduce the behavior

Other information

huangxunlei commented 2 years ago

【主线程中】

        val futures = mutableListOf<CompletableFuture<String>>()
                    for (i in 0 until list.size) {
             //  XxlJobContext.getXxlJobContext()  获取本次进程的 XxlJobContext 对象,将其传到异步线程中
                        val future = asyncService.send(list[i], XxlJobContext.getXxlJobContext())
                        futures.add(future)
                    }
                    futures.forEach { it.get() }

【异步线程中】

  @Async
    fun send(params: params, context: XxlJobContext?): CompletableFuture<String> {
    // 将主线程中传回来的参数 重新设置一下 
     context?.run { XxlJobContext.setXxlJobContext(this) 
     val isOk = XxlJobHelper.log(" 开始")
     println("isOK:$isOk")
}

不知道能不能解决你的问题 ?大概的原因是 我这边打印出来的日志 :我觉得这里并没有父子线程关系 ,只有主线程和异步线程而已, image

我这里配置核心线程数量为10 ,如下图: group为 main,如果真的要分父子线程的话 我觉得 主线程即 main 是父线程 image

这样说不知道能不能解决你的问题!我今天也遇到了!希望能帮到你

zerofxj commented 1 year ago

可以使用阿里巴巴 TransmittableThreadLocal 替换 XxlJobContext 内的 InheritableThreadLocal

  1. xxl-job-core pom 添加maven依赖

    <dependency>
       <groupId>com.alibaba</groupId>
       <artifactId>transmittable-thread-local</artifactId>
       <version>2.14.0</version>
    </dependency>
  2. 修改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)
  3. maven 编译打包 、

  4. 客户端使用-- 修改@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;
       }
    }

希望能够帮助到你