HashMapベースの高同時Map
通常のObjectを1つのMapで格納します.このMapの同時読み取りの頻度は高いですが、書き込みの頻度は低く、初期化や再マウント時にのみ書き込みます.読み書きの衝突はめったに起こらないが,一度発生するとMapの内部構造が乱れてしまう可能性があるため,Mapに同期ロックを付加せざるを得ない.
Copy On Writeのメカニズムを採用して、Mapの読み取り速度を強化することができます.
Copy On Writeはこのようなメカニズムです.共有データを読み込むときは、同期する必要はありません.私たちがデータを修正するときは、現在のデータをコピーして、このコピーに修正して、完成したら、修正したコピーで、元のデータを置き換えます.この方法をCopy On Writeと言います.
Oracleなどのリレーショナル・データベースのデータ変更は、Copy On Writeのパターンを採用します.Copy On Writeモードは同時読み込みのサポートは良いですが、同時修正時にバージョンが競合する問題があります.複数のスレッドが同じデータを同時に変更する場合、複数の変更コピーが同時に存在し、これらの変更コピーが互いに上書きされ、変更が失われる可能性があります.したがって、Oracleなどのデータベースでは、通常、バージョンチェックメカニズムが導入されます.つまり、バージョン番号フィールドを追加して、同時変更があるかどうかを検出します.同様のバージョン管理メカニズムはCVS、SVNなどのバージョン管理ツールに存在する.
私たちのCopy On Write Mapでは、古いデータを新しいデータで上書きすればよいので、バージョン管理の問題を考慮する必要はありません.これにより、私たちの実現が大幅に簡素化されます.
基本的な考え方は、読み書き操作をそれぞれ異なるMapで行い、書き終わるたびに2つのMapを同期させることです.コードは次のとおりです.
このMapを読み取るときは、普通のHashMapと同じくらい速いです.
書くときは、まず内部Mapをコピーして、このバックアップで修正して、変更した後、内部Mapをこの修正後のMapに等しくします.この方法は同期的に保護され,同時書き込み操作を回避した.このように、書くとき、費用がかなりかかります.なるべくputAll()methodを使います.
Copy On Writeのメカニズムを採用して、Mapの読み取り速度を強化することができます.
Copy On Writeはこのようなメカニズムです.共有データを読み込むときは、同期する必要はありません.私たちがデータを修正するときは、現在のデータをコピーして、このコピーに修正して、完成したら、修正したコピーで、元のデータを置き換えます.この方法をCopy On Writeと言います.
Oracleなどのリレーショナル・データベースのデータ変更は、Copy On Writeのパターンを採用します.Copy On Writeモードは同時読み込みのサポートは良いですが、同時修正時にバージョンが競合する問題があります.複数のスレッドが同じデータを同時に変更する場合、複数の変更コピーが同時に存在し、これらの変更コピーが互いに上書きされ、変更が失われる可能性があります.したがって、Oracleなどのデータベースでは、通常、バージョンチェックメカニズムが導入されます.つまり、バージョン番号フィールドを追加して、同時変更があるかどうかを検出します.同様のバージョン管理メカニズムはCVS、SVNなどのバージョン管理ツールに存在する.
私たちのCopy On Write Mapでは、古いデータを新しいデータで上書きすればよいので、バージョン管理の問題を考慮する必要はありません.これにより、私たちの実現が大幅に簡素化されます.
基本的な考え方は、読み書き操作をそれぞれ異なるMapで行い、書き終わるたびに2つのMapを同期させることです.コードは次のとおりです.
/*
* Copy On Write Map
*
* Write is expensive.
* Read is fast as pure HashMap.
*
* Note: extra info is removed for free use
*/
import java.lang.Compiler;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.HashMap;
import java.util.Collections;
public class ReadWriteMap implements Map {
protected volatile Map mapToRead = getNewMap();
// you can override it as new TreeMap();
protected Map getNewMap(){
return new HashMap();
}
// copy mapToWrite to mapToRead
protected Map copy(){
Map newMap = getNewMap();
newMap.putAll(mapToRead);
return newMap;
}
// read methods
public int size() {
return mapToRead.size();
}
public boolean isEmpty() {
return mapToRead.isEmpty();
}
public boolean containsKey(Object key) {
return mapToRead.containsKey(key);
}
public boolean containsValue(Object value) {
return mapToRead.containsValue(value);
}
public Collection values() {
return mapToRead.values();
}
public Set entrySet() {
return mapToRead.entrySet();
}
public Set keySet() {
return mapToRead.keySet();
}
public Object get(Object key) {
return mapToRead.get(key);
}
// write methods
public synchronized void clear() {
mapToRead = getNewMap();
}
public synchronized Object remove(Object key) {
Map map = copy();
Object o = map.remove(key);
mapToRead = map;
return o;
}
public synchronized Object put(Object key, Object value) {
Map map = copy();
Object o = map.put(key, value);
mapToRead = map;
return o;
}
public synchronized void putAll(Map t) {
Map map = copy();
map.putAll(t);
mapToRead = map;
}
}
このMapを読み取るときは、普通のHashMapと同じくらい速いです.
書くときは、まず内部Mapをコピーして、このバックアップで修正して、変更した後、内部Mapをこの修正後のMapに等しくします.この方法は同期的に保護され,同時書き込み操作を回避した.このように、書くとき、費用がかなりかかります.なるべくputAll()methodを使います.