Как работает InheritableThreadLocal, например, для переменного потока?

#java #multithreading #thread-local

#java #многопоточность #поток-локальный

Вопрос:

У меня есть следующая программа

 class ParentThread extends Thread{

    public ParentThread(String s) {
        super(s);
    }

    static InheritableThreadLocal tl = new InheritableThreadLocal();
    ChildThread c = new ChildThread("child");

    @Override
    public void run() {
        tl.set("pp");
        System.out.println("Thread :" Thread.currentThread().getName() " thread local value: " tl.get());
        c.start();
    }
}
class ChildThread extends Thread{
    public ChildThread(String child) {
        super(child);
    }

    @Override
    public void run() {
        System.out.println("Thread :" Thread.currentThread().getName() " thread local value: " ParentThread.tl.get());
    }
}
public class ThreadLocalDemo {
    public static void main(String[] args) {
        ParentThread p = new ParentThread("parent");
        p.start();
    }
}
  

Я получаю вывод в виде

 Thread :parent thread local value: pp
Thread :child thread local value: null
  

Я считаю, что, хотя я объявил ChildThread в качестве переменной экземпляра, метод запуска родительского потока отвечает за создание дочернего потока. Итак, почему вывод должен быть нулевым для дочернего элемента?

Когда я ставлю это

 ChildThread c = new ChildThread("child");
  

внутри метода run я получаю pp. Почему это так?

Ответ №1:

Из документов API:

когда создается дочерний поток, дочерний поток получает начальные значения для всех наследуемых локальных переменных потока, для которых родительский имеет значения.

Давайте перепишем ParentThread , чтобы быть более явным, не меняя никакой реализации. (Для демонстрации вообще нет особых причин ParentThread — основной поток будет работать просто отлично. Редактировать: я должен был продолжить эту мысль. Экземпляр ChildThread наследует локальные потоки наследуемых потоков из основного потока, а не ParentThread экземпляра.)

 class ParentThread extends Thread{
    static InheritableThreadLocal tl;
    static {
        tl = new InheritableThreadLocal();
    }

    /* pp */ ChildThread c;

    public ParentThread(String s) {
        super(s);
        this.c = new ChildThread("child");
    }

    @Override
    public void run() {
        tl.set("pp");
        System.out.println("Thread :" Thread.currentThread().getName() " thread local value: " tl.get());
        c.start();
    }
}
  

Там мы видим ChildThread , что конструктор вызывается раньше InheritableThreadLocal.set . Напишите new ChildThread() после tl.set(pp); , и значение должно быть видно.

InheritableThreadLocal это орехи. Я бы избегал этого, если не делал что-то вредоносное.

В общем, я настоятельно рекомендую избегать подклассов без необходимости и ThreadLocal .

Комментарии:

1. Я в замешательстве, потому что, как вы сказали, в документах API говорится: «когда создается дочерний поток, дочерний поток получает начальные значения …», Но дочерний поток создается только тогда, когда мы выполняем child.start() , и до этого я уже установил «pp»

2. Когда Thread объект создан. start просто начинает выполнение существующего потока.