理解Java中的InheritableThreadLocal

理解Java中的InheritableThreadLocal,java,multithreading,thread-local,inheritable-thread-local,Java,Multithreading,Thread Local,Inheritable Thread Local,我希望ParentThread将threadId设置为传递给其构造函数的值(比如p1)。然后它的所有子级都将threadId设置为p1.c1,p1.c2,依此类推。我编写了以下代码: public class InheritableThreadLocalDemo { public static void main(String[] args) { ParentThread pt = new ParentThread("p1"); pt.st

我希望
ParentThread
threadId
设置为传递给其构造函数的值(比如
p1
)。然后它的所有子级都将
threadId
设置为
p1.c1
p1.c2
,依此类推。我编写了以下代码:

public class InheritableThreadLocalDemo {

    public static void main(String[] args) 
    { 
        ParentThread pt = new ParentThread("p1"); 
        pt.start(); 
    } 
}

class ParentThread extends Thread { 
    static int childCount = 0;

    public static InheritableThreadLocal threadId = new InheritableThreadLocal() {
        public Object childValue(Object parentValue) 
        { 
            return parentValue.toString() + ".c" + (++childCount) ;  //this is line 18 where NullPointerException is occuring
        }
    }; 

    public ParentThread(String pThreadId) {
        threadId.set(pThreadId);
    }

    public void run() 
    { 
        System.out.println("Thread id:" + threadId.get());

        ChildThread childThread1 = new ChildThread(); 
        childThread1.start(); 

        ChildThread childThread2 = new ChildThread(); 
        childThread2.start();
    } 
} 
class ChildThread extends Thread { 

    public void run() 
    { 
        System.out.println("Child Thread Value :" + ParentThread.threadId.get()); 
    } 
} 
它打印:

Thread id:null
Exception in thread "Thread-0" java.lang.NullPointerException
    at com.mahesha999.examples.java.multithreading.ParentThread$1.childValue(InheritableThreadLocalDemo.java:18)
    at java.lang.ThreadLocal$ThreadLocalMap.<init>(Unknown Source)
    at java.lang.ThreadLocal$ThreadLocalMap.<init>(Unknown Source)
    at java.lang.ThreadLocal.createInheritedMap(Unknown Source)
    at java.lang.Thread.init(Unknown Source)
    at java.lang.Thread.init(Unknown Source)
    at java.lang.Thread.<init>(Unknown Source)
    at com.mahesha999.examples.java.multithreading.ChildThread.<init>(InheritableThreadLocalDemo.java:37)
    at com.mahesha999.examples.java.multithreading.ParentThread.run(InheritableThreadLocalDemo.java:30)
ParentThread.threadId.get()的
ChildThread.run()内部
。但是,现在我无法想象如何使这些
InheritableThreadLocal
变量在每个实例的每个线程中都是唯一的

第二季度。我应该怎么做


Q3.还是我错过了一些愚蠢的事情?“每个实例每个线程唯一”就是“仅每个实例唯一”,在这种情况下,我们根本不需要线程本地的概念?这就是为什么所有
ThreadLocal
变量按照惯例都应该是
static
的原因吗?

让我们看看相关的代码部分

class ParentThread extends Thread { 
    // ...
    public ParentThread(String pThreadId) {
        threadId.set(pThreadId);
    }
因此,将为运行构造函数的
Thread.currentThread()
设置
threadId
。这不能是正在构造的实例

    public void run() 
    { 
        System.out.println("Thread id:" + threadId.get());
现在,在新线程中,
threadId
将不会被初始化

        ChildThread childThread1 = new ChildThread(); 
这里取消了对
null
的引用


一般来说,我会避免使用
ThreadLocal
,以及大多数与全局变量相关的东西
InheritableThreadLocal
尽管它提供了娱乐功能,但我还是会尖叫着从它那里跑出来。

我想你的困惑是认为ThreadLocal与嵌入它的线程对象相关联。当调用线程本地方法时,它与任何对象相关联。您在此处有4个线程:

  • 主线
  • 父线程
  • 子线程#1
  • 子线程#2
  • 为父对象调用thread local set方法的构造函数在主线程(#1)内调用,将该线程的线程本地设置为非父线程(#2),因为它尚未开始运行

    下面是一个不重写thread类中任何内容的最小工作示例:

    package foo;
    
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class InheritableThreadLocalDemo {
    
        public static void main(String[] args) {
    
            final AtomicInteger childCount = new AtomicInteger();
    
            final InheritableThreadLocal<String> local = new InheritableThreadLocal<String>() {
                public String childValue(String parentValue) {
                    return parentValue.toString() + ".c" + (childCount.incrementAndGet());
                }
            };
    
            final Runnable child = () -> {
                System.out.println("Child Thread Value: " + local.get());
            };
    
            final Runnable parent = () -> {
                // The thread local value is associated with the thread that is running this block of
                // code.
                local.set("p1");
                System.out.println("Thread id:" + local.get());
    
                Thread c1 = new Thread(child);
                c1.start();
    
                Thread c2 = new Thread(child);
                c2.start();
            };
    
            final Thread parentThread = new Thread(parent);
            parentThread.run();
        }
    }
    

    我也在努力理解如何使用ThreadLocal:通过使它们成为
    静态的
    类级别,通过使它们成为
    非静态的
    实例级别,然后,在上面,您给出了具有本地方法级别的代码
    local
    InheritableThreadLocalDemo.main()
    的本地对象,这意味着
    InheritableThreadLocalDemo
    的任何其他方法都无法访问它。我在猜测当被
    父线程
    子线程
    、本地线程、实例线程或类线程本地线程继承时,它的作用域是什么?我猜它们将是
    父级
    子级
    中的实例级,对吗?关于“…运行线程”。在一个系统中,四个或八个CPU都是属于同一程序的活动运行线程,哪个线程是“运行线程”?不幸的是,很多操作系统API文档都使用“当前线程”这个短语,因为当您阅读操作系统源代码时,它是有意义的,但当您编写应用程序代码时,它就没有意义了。在API文档中看到“当前线程”的任何地方,都应该自动将其读取为“调用线程”
    package foo;
    
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class InheritableThreadLocalDemo {
    
        public static void main(String[] args) {
    
            final AtomicInteger childCount = new AtomicInteger();
    
            final InheritableThreadLocal<String> local = new InheritableThreadLocal<String>() {
                public String childValue(String parentValue) {
                    return parentValue.toString() + ".c" + (childCount.incrementAndGet());
                }
            };
    
            final Runnable child = () -> {
                System.out.println("Child Thread Value: " + local.get());
            };
    
            final Runnable parent = () -> {
                // The thread local value is associated with the thread that is running this block of
                // code.
                local.set("p1");
                System.out.println("Thread id:" + local.get());
    
                Thread c1 = new Thread(child);
                c1.start();
    
                Thread c2 = new Thread(child);
                c2.start();
            };
    
            final Thread parentThread = new Thread(parent);
            parentThread.run();
        }
    }
    
    class Thread {
        Map<ThreadLocal, Object> threadLocals;
        // getter
        Map<ThreadLocal, Object> getThreadLocals() { return threadLocals; }
    }
    
    Object thisThreadValue = Thread.currentThread().getThreadLocals().get(threadLocalInstance);