第五章 (1): 並行処理の構築部材

1時半就寝、7時起床。読み始めた本が面白くてついつい夜中まで起きてしまったけど、今朝は早く起きれたぞ。
この章はなかなか実際に使えそうなのでゆっくり読み進めたいと思います。

同期化コレクション

Collections.synchronizedListなど。こういった同期化コレクションは、個別のアクセスに対してはスレッドセーフだが、イテレーションや複合アクションをスレッドセーフに行うためにはクライアントサイドロックが必要。
例えばこれらのコレクションが返すイテレータは、ConcurrentModificationExceptionをスローする可能性がある。このような問題を解決するためには、前述の通りクライアントサイドロックを使って以下のようにする

public class SynchrnizedCollectionLock {

	private final List<MutablePoint> list = Collections.synchronizedList(new ArrayList<MutablePoint>());

	public void process() {

		// throws ConcurrentModificationException
		for (MutablePoint p : list) {
			// doSomething
		}

		synchronized (list) {
			for (MutablePoint p : list) {
				// doSomething
			}
		}

	}

}

か、コレクションのクローンを作ってスレッド拘束してしまうのが良い。

並行コレクション

ConcurrentHashMap, CopyOnWriteArrayList, BlockingQueue など。Java5.0から導入された、同期化コレクション (synchronizedCollection) を改良したスレッドセーフなコレクション群。

ConcurrentHashMap

ConcurrentModificationExceptionをスローしない、ロックを必要としない安全なイテレータを提供する、並行Mapの実装。通常のMapやSynchronizedMapのようにクライアントサイドロックは出来ないが、必要な複合アクションをアトミックに実行する機能が実装されている(put-if-absent, remove-if-equallなど)。但しsize()やisEmpty()などのメソッドは動的なので、あくまで推測値が返されるに過ぎない。

CopyOnWriteArrayList, CopyOnWriteArraySet

書き込みがあったらコピーを生成する、ArrayListの実装。ConcurrentHashMap同様、ConcurrentModificationExceptionをスローしないイテレータを提供する。実質的に不可変なオブジェクトにアクセスする際は同期化の必要が無いという点を利用し、コレクションに変更があった場合のみ補助配列をコピーすることによりスレッドセーフ性を得ている。
コレクションに変更がある度に補助配列のコピーが生成されるので、それなりにコストがかかる。要素の変更よりもイテレーションが多い場面で使うのに向いている。