当对数据结构的修改花费太长时间(无论出于何种原因)时,简单地等待和写锁定结构将不会成功。您只是无法预见何时有足够的时间在不阻塞任何读取的情况下执行修改。
您唯一能做的(尝试做的)就是将写操作中的时间减少到最低限度。正如@assylias 所说, CopyOnWrite* 通过在写入操作时克隆数据结构来做到这一点,并在操作完成时自动激活修改后的结构。
这样,读锁将花费克隆操作的持续时间加上切换引用的时间。您可以将其缩小到数据结构的一小部分:如果仅对象中的状态发生更改,则可以修改该对象的副本,然后将更复杂的数据结构中的引用更改为该副本。
另一种方法是在读取操作之前或之前进行复制。无论如何,您通常都会通过数据结构的 API 返回对象的副本,因此只需“缓存”该副本并在修改期间让读者访问缓存的副本。这也是数据库缓存所做的。
这取决于您的型号,什么最适合您。如果您对可以轻松复制的数据的写入很少,则 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);
}
对于这两种操作,读取时无需等待 .. 但需要切换参考。