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を同期させることです.コードは次のとおりです.
/*
 * 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を使います.