在Java中,在多线程环境中更改/读取字符串

时间:2017-06-11 08:23:43

标签: java multithreading

背景

我的系统使用访问令牌来访问平台API。

我有一个线程A来每2分钟更新一次访问令牌。

然后处理前端请求的其他线程将使用访问令牌进行API调用。

提供访问令牌的平台本身已实现了一些令牌重叠机制。也就是说,在生成新令牌后,旧令牌仍然可用30秒。

思想

我有如下界面:

public interface AccessTokenService {

    String fetchAccessToken();

    void refreshAccessToken();
}

显然,处理它的最简单且无错误的方法是使这两种方法同步。但是,由于令牌提供平台内置了令牌重叠。我不认为需要“同步”才能使其正常运营。此外,由于我的系统高度依赖于API调用,因此使方法同步会导致性能下降。

问题

我的问题是,JVM如何处理多线程字符串写/读。

比如说,字符串accessToken正在从“abc”更改为“def”。同时,一些线程正试图读取accessToken的值。读取的可能输出是什么?

  • abc(可能)
  • def(可能)
  • dbc(?)
  • 变化之间的杂乱内容(?)
  • null(?)

1 个答案:

答案 0 :(得分:1)

由于java中的字符串是不可变的,因此读取线程只能获取旧令牌或新令牌,但不能混合在一起。

引用的更新总是atomar(在这里:你的阅读线程可以读取旧引用或新引用,但不能混合在一起)。

只有一点要注意:存储当前令牌的字段必须声明为volatile,否则读取线程可能会缓存它们看到的某些值。

AccessTokenService的虚拟实现可能如下所示:

public class DummyAccessTokenService implements AccessTokenService {

    private volatile String currentToken = null;

    @Override
    public String fetchAccessToken() {
        return currentToken;
    }

    private int tokenNumber = 0;

    @Override
    public void refreshAccessToken() {
        currentToken = String.format("Token-%d", tokenNumber++);
    }

}