从声明位置以外的 class 访问 Java ThreadLocal 对象
Accessing Java ThreadLocal object from a class other than where it was declared
我正在声明一个 ThreadLocal 对象并设置如下值。
Public Class Blah {
private ThreadLocal<Set<Integer>> numberThreaLocalObj= new ThreadLocal<>();
void setValue() {
Set<Integer> numberSet = new HashSet<>();
numberSet .add(1);
threaLocalObj.set(numberSet)
}
}
是否可以在同一线程内在此 class 之外引用此 numberThreaLocalObj 变量?
我发现一些代码似乎清除了所有线程局部变量,但我只需要根据条件清除这个特定的线程局部变量。
不幸的是,这是一个继承的技术设计。
编辑 - 找到了我的回答中概述的解决方案。
它是一个线程本地的事实是无关紧要的。您在问:我可以从另一个 class 访问私有字段吗?
答案是:并非如此。如果您有想要访问此字段的 Blah 实例(它是一个非静态字段;因此,Blah 的每个实例都有一个本地线程),您可以使用 java.lang.reflection:
Field f = Blah.class.getDeclaredField("numberThreaLocalObj");
f.setAccessible(true);
ThreadLocal<?> t = f.get(someInstanceOfBlah);
t.set(null);
只要你添加适当的异常守卫就可以做到。
我可以使用下面的代码来识别我感兴趣的特定线程局部对象
代码来自之前的 post,由@lyaffe https://whosebug.com/users/509566/lyaffe
回答
我的线程局部对象在另一个class
private ThreadLocal<Set<Integer>> numberSetTL = new NamedThreadLocal<>("MY_NAMED_TL_NAME");
我稍微修改了代码以删除特定名称。要删除的 ThreadLocal 必须是 Spring NamedThreadLocal 对象。
private void cleanThreadLocals() {
try {
// Get a reference to the thread locals table of the current thread
Thread thread = Thread.currentThread();
Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
threadLocalsField.setAccessible(true);
Object threadLocalTable = threadLocalsField.get(thread);
// Get a reference to the array holding the thread local variables inside the
// ThreadLocalMap of the current thread
Class threadLocalMapClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
Field tableField = threadLocalMapClass.getDeclaredField("table");
tableField.setAccessible(true);
Object table = tableField.get(threadLocalTable);
// The key to the ThreadLocalMap is a WeakReference object. The referent field of this object
// is a reference to the actual ThreadLocal variable
Field referentField = Reference.class.getDeclaredField("referent");
referentField.setAccessible(true);
for (int i=0; i < Array.getLength(table); i++) {
// Each entry in the table array of ThreadLocalMap is an Entry object
// representing the thread local reference and its value
Object entry = Array.get(table, i);
if (entry != null) {
// Get a reference to the thread local object and remove it from the table
ThreadLocal threadLocal = (ThreadLocal)referentField.get(entry);
if(threadLocal instanceof NamedThreadLocal) {
if("MY_NAMED_TL_NAME".equalsIgnoreCase(threadLocal.toString())) {
threadLocal.remove();
LOG.debug(tlName + " - ThreadLocal found and removed.");
}
}
}
}
} catch(Exception e) {
// We will tolerate an exception here and just log it
throw new IllegalStateException(e);
}
}
您可以在 class 中将 ThreadLocal 变量设置为 Static 并在整个应用程序中全局访问它。来自官方 Spring 文档的示例
不要忘记清除 ThreadLocalExecutor 处理程序中的 ThreadLocal 变量(使用 afterExecute() ,它将在 Thread 释放到 ThreadPool 后执行),如下面的第 5.1 节所示 link:
我正在声明一个 ThreadLocal 对象并设置如下值。
Public Class Blah {
private ThreadLocal<Set<Integer>> numberThreaLocalObj= new ThreadLocal<>();
void setValue() {
Set<Integer> numberSet = new HashSet<>();
numberSet .add(1);
threaLocalObj.set(numberSet)
}
}
是否可以在同一线程内在此 class 之外引用此 numberThreaLocalObj 变量?
我发现一些代码似乎清除了所有线程局部变量,但我只需要根据条件清除这个特定的线程局部变量。
不幸的是,这是一个继承的技术设计。
编辑 - 找到了我的回答中概述的解决方案。
它是一个线程本地的事实是无关紧要的。您在问:我可以从另一个 class 访问私有字段吗?
答案是:并非如此。如果您有想要访问此字段的 Blah 实例(它是一个非静态字段;因此,Blah 的每个实例都有一个本地线程),您可以使用 java.lang.reflection:
Field f = Blah.class.getDeclaredField("numberThreaLocalObj");
f.setAccessible(true);
ThreadLocal<?> t = f.get(someInstanceOfBlah);
t.set(null);
只要你添加适当的异常守卫就可以做到。
我可以使用下面的代码来识别我感兴趣的特定线程局部对象 代码来自之前的 post,由@lyaffe https://whosebug.com/users/509566/lyaffe
回答我的线程局部对象在另一个class
private ThreadLocal<Set<Integer>> numberSetTL = new NamedThreadLocal<>("MY_NAMED_TL_NAME");
我稍微修改了代码以删除特定名称。要删除的 ThreadLocal 必须是 Spring NamedThreadLocal 对象。
private void cleanThreadLocals() {
try {
// Get a reference to the thread locals table of the current thread
Thread thread = Thread.currentThread();
Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
threadLocalsField.setAccessible(true);
Object threadLocalTable = threadLocalsField.get(thread);
// Get a reference to the array holding the thread local variables inside the
// ThreadLocalMap of the current thread
Class threadLocalMapClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
Field tableField = threadLocalMapClass.getDeclaredField("table");
tableField.setAccessible(true);
Object table = tableField.get(threadLocalTable);
// The key to the ThreadLocalMap is a WeakReference object. The referent field of this object
// is a reference to the actual ThreadLocal variable
Field referentField = Reference.class.getDeclaredField("referent");
referentField.setAccessible(true);
for (int i=0; i < Array.getLength(table); i++) {
// Each entry in the table array of ThreadLocalMap is an Entry object
// representing the thread local reference and its value
Object entry = Array.get(table, i);
if (entry != null) {
// Get a reference to the thread local object and remove it from the table
ThreadLocal threadLocal = (ThreadLocal)referentField.get(entry);
if(threadLocal instanceof NamedThreadLocal) {
if("MY_NAMED_TL_NAME".equalsIgnoreCase(threadLocal.toString())) {
threadLocal.remove();
LOG.debug(tlName + " - ThreadLocal found and removed.");
}
}
}
}
} catch(Exception e) {
// We will tolerate an exception here and just log it
throw new IllegalStateException(e);
}
}
您可以在 class 中将 ThreadLocal 变量设置为 Static 并在整个应用程序中全局访问它。来自官方 Spring 文档的示例
不要忘记清除 ThreadLocalExecutor 处理程序中的 ThreadLocal 变量(使用 afterExecute() ,它将在 Thread 释放到 ThreadPool 后执行),如下面的第 5.1 节所示 link: