InheritableThreadLocal и пулы потоков - PullRequest
       0

InheritableThreadLocal и пулы потоков

10 голосов
/ 04 сентября 2011

У меня есть проблема, которая, на мой взгляд, не имеет решения, но я все равно попробую здесь. Мое приложение использует пул потоков, и некоторые из потоков в этом пуле имеют наследуемую локальную переменную потока. Я расширил класс ThreadPoolExecutor, чтобы по существу очистить локальную переменную потока (в методе обратного вызова afterExecute), когда поток завершит выполнение.

Я понимаю, что когда у вас есть переменная InheritableThreadLocal, метод childValue () вызывается при инициализации потока, чтобы получить значение переменной ThreadLocal из родительского потока. Однако в моем случае при следующем использовании потока (после однократного использования) значение переменной InheritableThreadLocal равно нулю (поскольку оно было предварительно очищено в afterExecute). Есть ли способ доступа к локальной переменной потока родительского потока в beforeExecute, чтобы я мог по существу смоделировать, что метод childValue в InheritableThreadLocal делает во время создания потока.

Ответы [ 2 ]

5 голосов
/ 04 сентября 2011

Похоже, это плохой вариант использования для "наследуемой" разновидности локальных потоков.

Мой совет - просто использовать обычный TheadLocal и выполнить инициализацию явно;например, передача начального значения из родительского потока в дочерний поток в качестве параметра или чего-то подобного.

(я собирался предложить вам принудительно инициализировать локальный для потока дочерний поток, заставив его получить значение как можно скореекак это начинается. Но это рискует состязанием, например, если родительский поток возвращается в пул до того, как дочерний поток начинает выполняться.)


Я предполагаю, что еслиесть способ получить доступ к значению локальной переменной потока родительского потока из дочернего потока.

Нет способа сделать это.

И, судя по вашемудругие комментарии, я сомневаюсь, что вы имеете в виду «родитель» и «ребенок» в обычном смысле ... где родительский поток создает дочерний поток.

Но вот идея.Вместо того, чтобы пытаться разделить переменную между потоками, поделитесь фиксированным значением (например, идентификатором запроса) и используйте его в качестве ключа для общего Map.Используйте записи Map в качестве общих переменных.

1 голос
/ 02 августа 2017

Конструктор исполняемого объекта запускается в потоке вызывающей стороны, тогда как метод 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
...