可继承的线程本地和线程池

2022-09-03 15:31:11

我有一个问题,我真的不认为有解决方案,但我无论如何都会在这里尝试。我的应用程序使用线程池,并且此池中的某些线程具有可继承的线程局部变量。我已经扩展了 ThreadPoolExecutor 类,以便在线程完成执行时基本上清除线程局部变量(在 afterExecute 回调方法中)。

我知道,当你有一个 InheritableThreadLocal 变量时,当线程初始化以从父线程获取 ThreadLocal 变量的值时,将调用 childValue() 方法。但是,在我的情况下,下次使用线程时(使用一次后),InheritableThreadLocal变量的值为null(因为它之前在afterExecute中被清除)。有没有办法在execute之前访问父线程的线程局部变量,以便我基本上可以模拟 InheritableThreadLocal 中的子值方法在创建线程时执行的操作。


答案 1

这听起来像是线程局部的“可继承”风格的一个糟糕的用例。

我的建议是只使用常规并明确地进行初始化;例如,将初始值从父线程作为参数或其他东西传递给子线程。TheadLocal

(我建议你强制初始化线程 - 本地子线程,让它在启动后立即获取值。但这有竞争条件的风险。例如,如果父线程在子线程开始执行之前返回到池中。


我想我问的是,是否有办法从子线程访问父线程的线程局部变量的值。

没有办法做到这一点。

而且,从您的其他评论来看,我怀疑您的意思是正常意义上的“父母”和“孩子”......其中,父线程创建子线程。

但这是一个想法。与其尝试在线程之间共享变量,不如共享一个固定值(例如请求 ID),并将其用作共享的键。将这些条目用作共享变量。MapMap


答案 2

可运行的构造函数在调用方的线程中运行,而 run 方法在子线程中运行。您可以使用此事实将信息从父线程传输到子线程。看:

public class ThreadlocalApplication {
static public ThreadLocal<String> tenantId = new ThreadLocal<>();

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService executor = Executors.newCachedThreadPool();
    System.out.println(Thread.currentThread().getName());
    ThreadlocalApplication.tenantId.set("4711");
    executor.submit(new AsyncTask()).get();
    executor.shutdown();
}

static class AsyncTask implements Runnable {
    private String _tenantId;

    public AsyncTask() {
        System.out.println(Thread.currentThread().getName());
        _tenantId = ThreadlocalApplication.tenantId.get();
    }

    @Override
    public void run() {
        ThreadlocalApplication.tenantId.set(_tenantId);
        System.out.println(Thread.currentThread().getName());
        System.out.println(ThreadlocalApplication.tenantId.get());
    }
}
}

这就是结果

main
main
pool-1-thread-1
4711