データ構造の変更に時間がかかりすぎる場合 (何らかの理由で)、単純に待機して構造を書き込みロックしても成功しません。読み取りをブロックせずに変更を実行するのに十分な時間がいつあるかを予測することはできません。
あなたができる(やろうとする)唯一のことは、書き込み操作の時間を最小限に抑えることです。@assylias が述べたように、CopyOnWrite* は書き込み操作時にデータ構造を複製することでこれを行い、操作が完了すると変更された構造をアトミックにアクティブ化します。
これにより、読み取りロックには、クローン操作の期間と参照の切り替えにかかる時間と同じだけの時間がかかります。データ構造の小さな部分まで作業できます。オブジェクトの状態のみが変更された場合、そのオブジェクトのコピーを変更し、後でより複雑なデータ構造の参照をそのコピーに変更できます。
もう 1 つの方法は、読み取り操作時または読み取り操作の前にそのコピーを実行することです。いずれにせよ、データ構造の API を介してオブジェクトのコピーを返すことがよくあるため、そのコピーを「キャッシュ」し、変更中にリーダーがキャッシュされたコピーにアクセスできるようにします。これは、データベースキャッシュ 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);
}
どちらの操作でも、読み取り時に待機はありませんが、参照を切り替える必要がある間は待機します。