理解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);