要编写一个功能齐全的Java对象池,使用READ / WRITE锁定不是一个大问题。 我看到的问题是READ操作必须等到存储监视器(或类似的东西,取决于模型)被释放,这真的会减慢它。
因此,应满足以下要求:
READ(或GET)操作应该是即时的 - 使用某个键,应该立即返回最新版本的对象,而不等待任何锁定。
WRITE(CREATE / UPDATE) - 可能会排队,合理延迟,可能等待一些存储锁定。
任何代码示例?
我没有找到直接针对这个问题的问题。
它出现在一些讨论中,但我找不到一个完全致力于在Java中创建这样一个池的问题的问题。
答案 0 :(得分:0)
当对数据结构的修改花费太长时间(无论出于何种原因)时,简单地等待和写入锁定结构将不会成功。您无法预见何时您将有足够的时间执行修改而不会阻止任何读取。
你唯一可以做的(尝试做)是将写操作中的时间减少到最小。正如@assylias所述,CopyOnWrite *通过在写入操作时克隆数据结构并在操作完成时原子激活修改后的结构来完成此操作。
这样,读锁定的时间与克隆操作的持续时间加上切换引用的时间一样长。您可以将其工作到数据结构的小部分:如果对象中的状态发生更改,则可以修改该对象的副本,然后将更复杂的数据结构中的引用更改为该副本。
另一种方法是在读取操作之前或之前进行复制。通常你会通过数据结构的API返回一个Object的副本,所以只需“缓存”该副本,并在修改过程中让读者访问缓存的副本。这就是aso所做的数据库缓存。
这取决于您的型号什么是最适合您的。如果您对可以轻松复制的数据进行少量写入,则CopyOnWrite可能性能最佳。如果你有大量的写入,你可能最好提供一个结构的“读取”/缓存状态,并不时地进行切换。
AtomicReference<Some> datastructure = ...;
//copy on write
synchronized /*one writer*/ void change(Object modification)
throws CloneNotSupportedException {
Object copy = datastructure.clone();
apply(copy, modification);
datastructure.set(copy);
}
Object search(Object select) {
return datastructure.get().search(select);
}
// copy for read
AtomicReference<Some> cached = new AtomicReference<Some>(datastructure.get().clone());
synchronized void change(Object modification) {
apply(datastructure, modification);
cached.set(datastructure);
}
Object search(Object select) {
return cached.get().search(select);
}
对于这两种操作,读取时都没有等待..但是需要切换参考时间。
答案 1 :(得分:0)
在这种情况下,您可以简单地使用volatile变量来避免锁定读取器端并使用synchronized
方法保持写入独占。 volatile
将为读取增加很少或没有开销,但写入会有点慢。根据预期的吞吐量和读/写比率,这可能是一个很好的解决方案。
class Cache {
private volatile Map<K, V> cache; //Assuming map is the right data structure
public V get(K key) {
return cache.get(key);
}
//synchronized writes for exclusive access
public synchronized void put(K key, V value) {
Map<K, V> copy = new HashMap<> (cache);
V value = copy.put(key, value);
//volatile guarantees that this will be visible from the getter
cache = copy;
return value;
}
}
答案 2 :(得分:0)
这是一个完全无锁的Java对象池解决方案。 FYI
http://daviddengcn.blogspot.com/2015/02/a-lock-free-java-object-pool.html