SoFunction
Updated on 2025-04-05

How to solve the problem of traceId empty caused by asynchronous threads

The problem of traceId being empty caused by asynchronous threads

1. Use thread pool

import ;
import org.;
import ;
import ;
import ;
import ;
import ;
import ;
import ;

/**
  * xxx task thread pool configuration
  */
@Configuration
@ConfigurationProperties(prefix = "-xx")
@Data
public class XxxThreadPoolConfiguration {

  /**
   * Minimum number of threads to keep alive
   */
  private int corePoolSize = 8;

  /**
   * Maximum number of threads in the pool
   */
  private int maxPoolSize = 16;

  /**
   * Time in seconds to keep excess idle threads alive
   */
  private long keepAliveTime = 60;

  /**
   * queue size
   */
  private int queueSize = 1000;

  @Bean("xXxExecutor")
  public ThreadPoolExecutor xXxExecutor() {
    ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize,
            keepAliveTime, , new LinkedBlockingQueue<>(queueSize));
    (runnable -> {
      Thread thread = new Thread(runnable);
      ("commonExecutor-" + ());
      return thread;
    });
    (new ());
    return executor;
  }



  public static class MdcThreadPoolExecutor extends ThreadPoolExecutor {

    public MdcThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
      super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
      // Before the task is executed, obtain the traceId from the current thread (if it is called by the main thread, it is the main thread's MDC) and set it to the MDC of the thread that is about to execute the task      String traceId = ("traceId");
      ("traceId", traceId);
      (t, r);
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
      // Clear traceId in MDC after task execution (avoid memory leaks and other problems, free up resources)      ("traceId");
      (r, t);
    }
  }
}


2. Use

import ;
import ;

@Service
public class XxxController{
// Constructor injection  public OutChargeOrderPushController(
          @Qualifier("xXxExecutor")ThreadPoolExecutor executor
  ) {
     = executor;
  }
// When using the asynchronous operation method, just pass the executor in
}

Summarize

The above is personal experience. I hope you can give you a reference and I hope you can support me more.