InheritableThreadLocal和线程池

时间:2011-09-04 00:12:15

标签: java multithreading threadpool

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

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

2 个答案:

答案 0 :(得分:5)

听起来这对于线程本地人的“可继承”风格来说是一个糟糕的用例。

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

(我建议你强制初始化线程本地的子线程,让它一旦启动就获取它。但这会冒一个竞争条件;例如,如果父线程返回到池中在子线程开始执行之前。)


  

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

没有办法做到这一点。

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

但这是一个想法。不是尝试在线程之间共享变量,而是共享固定值(例如,请求ID),并将其用作共享Map的密钥。使用Map条目作为共享变量。

答案 1 :(得分:1)

runnable的构造函数在调用者的线程中运行,而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