#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
просто начинает выполнение существующего потока.