首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ThreadLocal.get()返回null,即使在前面初始化它时也是如此

ThreadLocal.get()返回null,即使在前面初始化它时也是如此
EN

Stack Overflow用户
提问于 2019-01-29 21:01:43
回答 1查看 5.4K关注 0票数 3

我觉得我可能误解了这件事的运作方式。

我有这样的代码:

代码语言:javascript
复制
public Timestamp startTransaction() {
    cleanupTransactionContext();
    Timestamp timestamp = getLatestTimestamp();
    initThreadLocalVariables(timestamp);
    return getTransactionContext().toString();
}

private Timestamp getTransactionContext() {
    if (transactionContext == null) {
        throw new BadTransactionStateException();
    }
    return transactionContext.get();
}

private void initThreadLocalVariables(Timestamp timestamp) {
    setTransactionContext(timestamp);
}

private void setTransactionContext(Timestamp ts) {
    if (this.transactionContext == null) {
        this.transactionContext = new ThreadLocal<>();
    }
    this.transactionContext.set(ts);
}

我的理解是,ThreadLocal.get()永远不应该返回null (从JDK):

代码语言:javascript
复制
/**
 * Returns the value in the current thread's copy of this
 * thread-local variable.  If the variable has no value for the
 * current thread, it is first initialized to the value returned
 * by an invocation of the {@link #initialValue} method.
 *
 * @return the current thread's value of this thread-local
 */
public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

因为我之前已经在setTransactionContext中显式地设置了它,它依次调用ThreadLocal.set,它应该创建映射:

代码语言:javascript
复制
   /**
 * 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);
}

但是,有时我会在:return getTransactionContext().toString();中获得空指针异常。其他时候,它工作得很好,所以我怀疑某种比赛条件,我只是不知道它会是什么样子。

PS:时间戳类如下所示:

代码语言:javascript
复制
public final class Timestamp {

private final long timeInMilliseconds;
private final long sequenceNumber;

}

但是请注意,这是一个简化的代码版本,它不包括几个检查,以确保这不是null。getLatestTimeStamp值本身是正确的,不会设置为null。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-01-30 21:01:48

正如@shmosel所指出的,问题在于这段代码不是原子的:

代码语言:javascript
复制
private void setTransactionContext(Timestamp ts) {
  if (this.transactionContext == null) {
    this.transactionContext = new ThreadLocal<>();
  }
  this.transactionContext.set(ts);
}

因此,两个线程可能正在创建ThreadLocal并相互干扰。将线程的创建移动到变量声明中可以解决这个问题,因为ThreadLocal上的后续操作默认是线程安全的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54429504

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档