我很好奇这个缓存想法是否保证有效:
@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
不是完全不可变的,那么就不安全,因为使用者线程可能会看到未完全构造的对象。此外,如果缓存的是基本类型,且其赋值不是原子的(double
、long
),则使用者线程可能会看到垃圾(一半赋值)。
编辑:
根据Java Concurrency in Practice ,如果满足以下条件,则可以安全地发布对象而无需同步:
- 构建后其状态无法修改
- 其所有字段均声明为
final
- 已正确构造(
this
关键字在构造期间不会转义)
关于java - 这个缓存线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25835354/