能否在给定线程对象的情况下访问ThreadLocal变量?

5
我想在另一个线程中访问线程本地变量。例如,我有一个线程对象A用于线程1,它有一个本地变量L1。还有另一个线程Thread-2,如何在Thread-2中访问L1?谢谢。

2
不可以,那将违反“线程本地”的含义。如果您不想让它成为“线程本地”,则不要使用ThreadLocal。 - user207421
将变量放置在父类中。 - Scary Wombat
它在另一个第三方库中,我无法更改。 :( - zjffdu
2
如果这是第三方库中的内容,你几乎肯定不想去改变它们的线程假设。多线程是一件非常精确的事情,如果他们创建了一个ThreadLocal对象,而你又在其他线程中“窃取”了它,那么很容易出现微妙且令人困惑的错误。 - yshavit
1
@zjffdu 如果这是第三方库中的内容,那么你正在违反它们的设计。他们将其设置为线程本地,因为他们希望它是线程本地的。不要这样做。 - user207421
2个回答

2
不行,因为存在内存可见性问题。所有ThreadLocal基础设施都假定对threadlocal对象的访问是线程限制的。如果另一个线程篡改threadLocal对象的内容,那么就没有内存屏障来让原始所有者线程知道它需要更新缓存版本的该对象,并且JIT在推理它可以重新排序哪些指令时不知道考虑其他线程的修改;如果您更新它,则原始线程仍然可能看到旧版本,而不知道发生了更改。

这还加上yshavit所观察到的事实,即通常情况下篡改第三方库的内部是不好的想法。


1

是的,您可以使用反射来实现。但您不应该这样做。正如其他人指出的那样:您很可能会破坏事物或得到意外的结果。

但纯粹为了学术演示,这个方法确实可以实现您所要求的功能:

@NotThreadSafe
Object getValueForThread(ThreadLocal<?> threadLocal, Thread thread) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, NoSuchFieldException {
    Method getMap = ThreadLocal.class.getDeclaredMethod("getMap", new Class<?>[]{Thread.class});
    getMap.setAccessible(true);
    Object map = getMap.invoke(threadLocal, thread);
    Class<?> clazz = map.getClass();
    Method getEntry = clazz.getDeclaredMethod("getEntry", new Class<?>[]{ThreadLocal.class});
    getEntry.setAccessible(true);
    Object entry = getEntry.invoke(map, threadLocal);
    Field value = entry.getClass().getDeclaredField("value");
    value.setAccessible(true);
    return value.get(entry);
}

或者至少,它可能会执行你的请求。由于没有可见性保证,调用此方法的线程可能会看到过期的值。所以再次强调:不要这样做


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接