admin管理员组

文章数量:1123192

Somehow when I try to set value to the InheritableThreadLocal field while creating an object of class that inherites Thread I get strange behavior: my object doesn't have the value I set while invoking constructor when the execution reaches the printing line in run() method. At the same time when I try to run a thread that inherites my class it sees the value I set while doing previos creation.

I tried to run the following code:

public class InheritableThreadLocalExample {

  public static void main(String[] args) {
    ThreadOne threadOne = new ThreadOne("user-one", "thread-one");
    threadOne.start();
    ThreadTwo threadTwo = new ThreadTwo("user-two", "thread-two");
    threadTwo.start();
  }

  public static class ThreadOne extends Thread {

    protected static final InheritableThreadLocal<String> USERNAME = new InheritableThreadLocal<>();

    public ThreadOne(String username, String threadName) {
      super(threadName);
      USERNAME.set(username);
    }

    @Override
    public void run() {
      System.out.println(Thread.currentThread().getName() + ". Username: " + USERNAME.get());
    }
  }

  public static class ThreadTwo extends ThreadOne {
    public ThreadTwo(String username, String threadName) {
      super(username, threadName);
    }
  }

}

The output is:

thread-two. Username: user-one
thread-one. Username: null

Why is this happening?

Somehow when I try to set value to the InheritableThreadLocal field while creating an object of class that inherites Thread I get strange behavior: my object doesn't have the value I set while invoking constructor when the execution reaches the printing line in run() method. At the same time when I try to run a thread that inherites my class it sees the value I set while doing previos creation.

I tried to run the following code:

public class InheritableThreadLocalExample {

  public static void main(String[] args) {
    ThreadOne threadOne = new ThreadOne("user-one", "thread-one");
    threadOne.start();
    ThreadTwo threadTwo = new ThreadTwo("user-two", "thread-two");
    threadTwo.start();
  }

  public static class ThreadOne extends Thread {

    protected static final InheritableThreadLocal<String> USERNAME = new InheritableThreadLocal<>();

    public ThreadOne(String username, String threadName) {
      super(threadName);
      USERNAME.set(username);
    }

    @Override
    public void run() {
      System.out.println(Thread.currentThread().getName() + ". Username: " + USERNAME.get());
    }
  }

  public static class ThreadTwo extends ThreadOne {
    public ThreadTwo(String username, String threadName) {
      super(username, threadName);
    }
  }

}

The output is:

thread-two. Username: user-one
thread-one. Username: null

Why is this happening?

Share Improve this question asked 7 hours ago bepopovbepopov 254 bronze badges 1
  • 3 Think about which thread executes the constructor of ThreadOne and when it does so. – Holger Commented 7 hours ago
Add a comment  | 

1 Answer 1

Reset to default 3

The constructor of ThreadOne is executed by the main thread, therefore, the statement USERNAME.set(username); inside this constructor sets the value for the main thread. But the actual values of the inheritable thread locals of the main thread were copied in the constructor of Thread, i.e. the preceding super(threadName);, already.

Therefore, the first thread inherits the state before the first USERNAME.set(username); call whereas the second thread inherits the state after that call; the inheritance relationship is irrelevant, as we can demonstrate:

public class InheritableThreadLocalExample {
  public static void main(String[] args) {
    ThreadOne threadOne = new ThreadOne("user-one", "thread-one");
    printValue();
    threadOne.start();
    Thread threadTwo = new Thread(
                       InheritableThreadLocalExample::printValue, "thread-two");
     // things happening after Thread's constructor are irrelevant:
    ThreadOne.USERNAME.set("user-two");
    threadTwo.start();
  }

  static void printValue() {
    System.out.println(Thread.currentThread().getName()
                     + ". Username: " + ThreadOne.USERNAME.get());
  }

  public static class ThreadOne extends Thread {
    protected static final InheritableThreadLocal<String> USERNAME
                                  = new InheritableThreadLocal<>();

    public ThreadOne(String username, String threadName) {
      super(threadName);
      USERNAME.set(username);
    }

    @Override
    public void run() {
      printValue();
    }
  }
}
main. Username: user-one
thread-one. Username: null
thread-two. Username: user-one

We can easily set the intended values in the main thread without subclasses:

public class InheritableThreadLocalExample {
  static final InheritableThreadLocal<String> USERNAME
                                            = new InheritableThreadLocal<>();

  public static void main(String[] args) {
    USERNAME.set("user-one");
    Thread threadOne = new Thread(
        InheritableThreadLocalExample::printValue, "thread-one");
    USERNAME.set("user-two");
    Thread threadTwo = new Thread(
        InheritableThreadLocalExample::printValue, "thread-two");

    // demonstrate that each thread has its own value
    // and main doesn't need a value:
    USERNAME.remove();

    threadOne.start();
    threadTwo.start();
  }

  static void printValue() {
    System.out.println(Thread.currentThread().getName()
                     + ". Username: " + USERNAME.get());
  }
}
thread-one. Username: user-one
thread-two. Username: user-two

本文标签: javaUnable to set value to InheritableThreadLocal field in class inherited ThreadStack Overflow