java - 这个缓存线程安全吗?

标签 java multithreading caching guava

我很好奇这个缓存想法是否保证有效:

@RequiredArgsConstructor @Getter class CacheEntry {
    static CacheEntry get(String string, int start) {
        int hash = string.hashCode() ^ start; // or something better
        int index = hash & (cache.length-1);
        CacheEntry result = cache[index];
        if (result!=null && result.matches(string, start)) return result;
        result = new CacheEntry(string, start, computeSomething(string, start));
        cache[index] = result;
        return result;
    }

    private boolean matches(String string, int start) {
        if (string.equals(this.string)) return false;
        if (start == this.start) return false;
        return true;
    }

    private static ImmutableSomething computeSomething(String string, int start) {
        ...
    }

    private static final CacheEntry[] cache = new CacheEntry[256];

    private final String string;
    private final int start;

    private final ImmutableSomething something;
}

注释来自lombok 。想象一下每个人都按照其名字所说的去做。

目标是节省对 computeSomething 的调用,并最大限度地减少分配。

缓存既不是同步的也不是线程本地的。无法保证一个线程会看到另一个线程完成的更新。这是可以接受的。也不能保证一个线程不会覆盖另一个线程的条目。这也是可以接受的。

在我编写的一个小型基准测试中,与 sane caching alternatives 相比,它带来了很好的加速。 。我关心的是正确性:线程看到无效条目(例如,包含错误的某物)的情况是否会发生?

最佳答案

只要 CacheEntry 是一个适当的不可变对象(immutable对象)(而不是仅仅有效的不可变对象(immutable对象)),这就可以工作。这是因为不可变对象(immutable对象)可以安全地发布而无需同步,并且对象引用分配是原子的。

换句话说,如果 CacheEntry 不是完全不可变的,那么就不安全,因为使用者线程可能会看到未完全构造的对象。此外,如果缓存的是基本类型,且其赋值不是原子的(doublelong),则使用者线程可能会看到垃圾(一半赋值)。

编辑:
根据Java Concurrency in Practice ,如果满足以下条件,则可以安全地发布对象而无需同步:

  • 构建后其状态无法修改
  • 其所有字段均声明为final
  • 已正确构造(this 关键字在构造期间不会转义)

关于java - 这个缓存线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25835354/

相关文章:

c++ - 以原子方式读取非原子变量?

java - ExecutorService 应该在 bean 的整个生命周期中都处于 Activity 状态,或者应该具有狭窄的(方法)范围

ruby-on-rails - 来自 cloudfront 的动态内容 - 我可以放置来自 Rails 的 API 结果 (JSON) 吗?

jquery - Rails 中没有缓存时间戳的资源 URL

java - 如何以非阻塞方式从 WebClient bodyToMono 或 toEntity 获取对象

Java IEEE 754 float 到 IBM float byte[4] 转换

java - 以编程方式执行 shell 命令不起作用

swift - 为什么 Dispatchqueue.main.async 仍然在主线程中执行 block ?

java - 什么是一致性构造函数?

multithreading - get_multi/set_multi 原子?