ThreadLocal是线程安全的吗?

9
例如,我们有一个静态的ThreadLocal字段和一个setter方法:
private static final ThreadLocal threadLocalField = new ThreadLocal;

public static void getSXTransaction() {
  threadLocalField.set(new MyValue());
}

我想知道这里的线程安全性保证是什么,因为在java.lang.ThreadLocal#set方法中没有隐式同步。我知道ThreadLocal类天生具有完全的线程安全性,但我不明白它是如何实现的。
以下是该方法的源代码:
/**
 * Sets the current thread's copy of this thread-local variable
 * to the specified value.  Most subclasses will have no need to 
 * override this method, relying solely on the {@link #initialValue}
 * method to set the values of thread-locals.
 *
 * @param value the value to be stored in the current thread's copy of
 *        this thread-local.
 */
public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}
2个回答

20

这是安全的,因为getMap返回给定线程(即当前线程)的映射。没有其他线程会与其混淆。所以真正的问题在于getMap的实现要确保对于任何线程都是安全的 - 就我所见,它只是将其委托给Thread对象内的一个字段。我不确定是否有getMap传递给了除了当前线程之外的任何线程 - 如果是这样的话,那可能会很棘手 - 但我猜想已经仔细编写以确保这不是个问题 :)


2
我认为使用ThreadLocal是一种不好的做法,看起来像是一个hack。 - DontRelaX
2
@DontRelaX:我不明白这与问题或答案有什么关系。我有点同意,尽管有一些上下文的概念有时可能会有所帮助,但我不认为这条评论对这个问题或答案有任何帮助。 - Jon Skeet
@Jon “所以这真的取决于getMap的实现,以确保对于任何线程都是可以的” - 感谢您为我澄清这一点! - iozee
@JonSkeet 当然,我同意。我只是说这种hack可能会破坏弱线程安全性。当然,通常情况下没有人会这样做。 - Chao
2
@Richard:没错,我的观点是,在几乎每个Java问题的Stack Overflow答案中都添加“如果您使用反射来违反正常行为,则此答案均不适用”是毫无意义的。 - Jon Skeet
显示剩余2条评论

0
继Jon的回答之后,我同意,该映射是当前线程的唯一属性。
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

这个ThreadLocalMap存储了一个表格,其中只引用调用ThreadLocal对象(位于堆空间,即所有线程共享)以获取哈希索引到表格。但实际值存储在此表格中,该表格是每个线程的。

因此,如果您的ThreadLocal对象在多个线程之间共享,并且每个线程同时调用get或set,则它们实际上是在自己包含在ThreadLocalMap内的表格副本中设置值,该表格作为非静态字段存储在Thread类中。


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