javax.cache按引用存储与按值存储
我不熟悉java缓存,我试图理解按值存储和按引用存储之间的区别 我在下面引用了java.cache文档中的一段 " 复制存储在缓存中的条目以及从缓存返回的条目的目的是允许应用程序继续改变键和值的状态,而不会对缓存中的条目造成副作用。 "javax.cache按引用存储与按值存储,java,caching,jcache,Java,Caching,Jcache,我不熟悉java缓存,我试图理解按值存储和按引用存储之间的区别 我在下面引用了java.cache文档中的一段 " 复制存储在缓存中的条目以及从缓存返回的条目的目的是允许应用程序继续改变键和值的状态,而不会对缓存中的条目造成副作用。 " 上面提到的“副作用”是什么?我们如何选择如何在实践中存储 这是为了防止并发修改可变对象。副作用是其他线程正在使用该对象进行某些操作 例如,如果您有一个具有多个线程的银行程序,该程序具有一个整数对象缓存,这些整数对象表示它们之间共享的银行帐号。假设线程1从缓存中检
上面提到的“副作用”是什么?我们如何选择如何在实践中存储 这是为了防止并发修改可变对象。副作用是其他线程正在使用该对象进行某些操作 例如,如果您有一个具有多个线程的银行程序,该程序具有一个整数对象缓存,这些整数对象表示它们之间共享的银行帐号。假设线程1从缓存中检索一个数字,然后开始对其执行操作。操作线程1时,对象线程2检索同一对象,并开始操作它。由于它们同时以不协调的方式操纵同一对象,因此结果是不可预测的。对象本身甚至可能损坏
如果在将对象保存到缓存时只存储对象的副本,并在从缓存检索对象时分发对象的副本,则按值存储可以消除并发编程中的这一常见问题 这个问题很好,因为答案并不容易。真正的语义在缓存实现之间略有不同 按引用存储: 缓存存储并返回相同的对象引用
Object key = ...
Object value = ...
cache.put(key, value);
assert cache.get(key) == value;
assert cache.iterator().next().getKey() == key;
如果在存储值后对键进行变异,则会出现不明确的情况。使用HashMap
或ConcurrentHashMap
时效果相同
使用“按引用存储”,以:
- 最大化性能/最小化处理开销
- 当数据适合Java堆时
- 如果要在存储值后对其进行变异。这对性能很有用,但不是推荐的做法,因为您必须处理并发问题,并且使用依赖于引用存储语义
assert cache.get(key) != cache.get(key);
JCache实现可能会有更大的变化,当它进入细节时。例如:
Map map = cache.getAll(...);
assert map.get(key) != map.get(key);
这是预期语义中的一个矛盾。我们希望映射内容是稳定的,否则缓存需要在每次访问时返回值的副本。JCache规范没有为此强制执行具体的语义。魔鬼在于细节
由于每个缓存实现都会在存储时复制密钥,因此您将获得额外的安全性,即缓存内部数据结构是正常的,但由于共享值引用,应用程序仍有机会中断
Object key = ...
Object value = ...
cache.put(key, value);
assert cache.get(key) == value;
assert cache.iterator().next().getKey() == key;
我的个人结论(我愿意讨论):
由于引用存储是一个可选的JCache特性,请求它将意味着限制应用程序使用的缓存实现的数量。如果不依赖引用存储语义,请始终使用值存储
但是,不要让应用程序依赖于您认为通过“按值存储”可能获得的语义。在将任何对象的引用传递到缓存或从缓存检索其引用后,切勿对其进行变异
如果仍有疑问,请咨询您的缓存供应商。IMHO的良好做法是记录实施细节。一个很好的例子(因为我花了很多心思…)是《嗨,广告人》!你的答案是正确的(并且得到了+1),但是,这个主题还有一些细节。请看我渴望的回答。。。。