面试面试汇总DevOps

如何在子线程和线程池中使用 ThreadLocal 传输上下文

2018-09-28  本文已影响464人  _晓__

问题举例

问题解决

Spring框架 @Async

public final class ThreadContext {
    private static final ThreadLocal<Long> USER_ID_LOCAL = new InheritableThreadLocal<>();

    public static Long getUserId() {
        return USER_ID_LOCAL.get();
    }

    public static void setUserId(Long userId) {
        USER_ID_LOCAL.set(userId);
    }

    public static void clear() {
        USER_ID_LOCAL.remove();
    }
}

public class BusinessTask {

    @Async
    public void handle() {
        System.out.println(ThreadContext.getUserId());
    }
}

maven pom 配置:

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>transmittable-thread-local</artifactId>
</dependency>

这只是配置线程池方式之一,这里不阐述太多,只是举例说明使用:

public class AsyncThreadPoolConfiguration implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
        // TODO 配置具体参数
        threadPool.initialize();

        // 重点:使用 TTL 提供的 TtlExecutors
        return TtlExecutors.getTtlExecutor(threadPool);
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new SimpleAsyncUncaughtExceptionHandler();
    }
}

public final class ThreadContext {
    // 只需替换 InheritableThreadLocal 为 TransmittableThreadLocal 即可
    private static final ThreadLocal<Long> USER_ID_LOCAL = new TransmittableThreadLocal<>();

    public static Long getUserId() {
        return USER_ID_LOCAL.get();
    }

    public static void setUserId(Long userId) {
        USER_ID_LOCAL.set(userId);
    }

    public static void clear() {
        USER_ID_LOCAL.remove();
    }
}

public class BusinessTask {

    @Async
    public void handle() {
        System.out.println(ThreadContext.getUserId());
    }
}

通过解决了 Spring @Async 注解的问题,即可举一反三,CompletableFuture.supplyAsync 和 Executor 亦可以在这两种方法处理。
线程池中传输必须配合 TransmittableThreadLocal 和 TtlExecutors 使用。

PS:

上一篇下一篇

猜你喜欢

热点阅读