不一致的同步违规

mic*_*nko 5 java multithreading findbugs sonarqube

我在以下方法中对 return 语句进行了此违规:

protected Token getAccessToken() {  
    synchronized (this) {
        if (token == null || isExpired(token))
            token = createToken();
    }

    return token; // <-- Inconsistent synchronization of blablabla.token; locked 75% of time
}
Run Code Online (Sandbox Code Playgroud)

是否存在与token字段相关的可见性问题?据我了解,synchronized块令牌应该具有其最新值。

我错过了什么还是误报?

Mar*_*eel 4

考虑以下:

  • 线程1:进入方法
  • 线程2:进入方法
  • Thread1:进入同步块,token不为空且未过期
  • 线程1:退出同步块
  • Thread2:进入同步块,token不为空但已过期
  • 线程2:分配新令牌
  • 线程1:返回token(可能是线程2分配的新值,也可能是旧值)
  • 线程2:退出同步块
  • 线程2:返回(新)令牌

如果你想做你正在做的事情,那么token可能需要是易失性的(但这可能不是一个足够的保证!),或者你应该始终从同步块返回值,或者将值分配token给内部的局部变量同步块并从外部返回该局部变量。

这甚至没有考虑其他方法同时可能对令牌执行的操作。如果另一个(同步或非同步)方法token也修改了(例如 allocates null),那么您的情况可能会更糟,因为您假设thattoken不为 null (正如您刚刚检查的那样),而实际上它可能是null now

  • 只是为了强调您对OP的观点,我想进一步继续您的示例:假设线程1返回旧值,线程2返回新值。然后,两个线程首先使用其值参与与线程 2 的其他同步交互,然后线程 1 使用其(较旧的)值。您可能会摸不着头脑,想知道如何在新令牌之后使用过期令牌。 (2认同)