Java同時プログラミング実戦ノート(三):対象の組合せ


ここではコンビネーションモードをご紹介します.スレッドセキュリティのクラスを記述する重要な考え方は、既存のスレッドセキュリティコンポーネントをより大規模なコンポーネントまたはプログラムに組み合わせることです.スレッドセキュリティクラスを設計するには、次の3つの基本要素が必要です.
1.オブジェクトの状態を構成するすべての変数を特定します.
2.拘束状態変数の不変性条件を特定します.
3.オブジェクトステータスの同時アクセス管理ポリシーを確立します.
同期要件の収集
クラスのスレッドのセキュリティを確保するには、そのスレッドのセキュリティを確保する必要があります.
不変性条件は、同時アクセスの場合に破壊されません.同様に、操作にはいくつかの
ステータス遷移が有効かどうかを判断するには,後験条件を用いる.次のステータスが現在のステータスに依存する必要がある場合、この操作は複合操作でなければなりません.オブジェクトの不変性と事後条件が分からないと、スレッドのセキュリティが確保されません.状態変数の有効値や状態変換における様々な制約条件を満たすには,原子性とパッケージング性を用いる必要がある.
依存状態の操作
一部のオブジェクトのメソッドには、ステータスベースの
削除前の非空判定のような先行条件を依存状態の操作と呼ぶ.先行条件が真である場合に実行される動作を実行するには、キューBlocking Queueや信号量Semaphoreをブロックするなどの既存のライブラリ内のクラスによって依存状態の動作を実現する簡単な方法があります.
ステータスの所有権
オブジェクトが所有する状態をカプセル化し、逆にカプセル化された状態に所有権を持つこともできます.ステータス変数の所有者は、変数のステータスの整合性を維持するためにどのロックプロトコルを使用するかを決定します.
インスタンスのクローズド
カプセル化は、スレッドセキュリティクラスの実装プロセスを簡略化し、通常は「カプセル化」と略称されるインスタンス閉鎖メカニズムを提供します.あるオブジェクトが別のオブジェクトにカプセル化されると、カプセル化されたオブジェクトにアクセスできるすべてのコードパスが知られている.データをオブジェクト内にカプセル化することで、データのアクセスをオブジェクトのメソッドに制限でき、スレッドがデータにアクセスするときに常に正しいロックを持つことを容易にします.
Javaモニタモード
Javaモニタモードに従うオブジェクトは、オブジェクトのすべての可変状態をカプセル化し、オブジェクト独自の内蔵ロックで保護します.Javaモニタモードは、いずれのロックオブジェクトに対しても、そのロックオブジェクトを最初から最後まで使用すれば、オブジェクトの状態を保護するために使用できる符号化された規則にすぎません.
public class PrivateLock{
	private final Object myLock = new Object();
	@GuardedBy("myLock")
	Widget widget;
	void someMethod(){
		synchronized (myLock) {
			// Widget 
		}
	}
}

プライベートロックオブジェクトを使用する利点は、ロックをカプセル化し、顧客コードがロックされないようにすることです.
スレッドセキュリティの委任
1つのクラスに単一のスレッドセキュリティのステータス変数しか存在しない場合、そのスレッドセキュリティは、そのスレッドセキュリティのステータス変数に委任できます.複数の状態変数の場合、
複数のスレッドセキュリティのステータス変数が互いに独立している場合は、スレッドセキュリティを委任することもできます.逆に、複数のステータス変数が独立していない場合は、スレッドセキュリティをスレッドセキュリティステータス変数に委任することはできません.
既存のスレッドセキュリティクラスに機能を追加
主に、クライアントにロックをかける方法は2つありますが、ロック対象がクライアントのロックまたは外部のロックを実現する際に同じロックを使用することを確認します.
@ThreadSafe
public class ListHelper{
	public List list = Collections.synchronizedList(new ArrayList());
	public boolean putIfAbsent(E x){
		synchronized(list){// List 
			boolean absent = !list.contains(x);
			if(absent)
				list.add(x);
			return absent;
		}
	}
}

もう一つのより良い方法は組み合わせを使うことです
@ThreadSafe
public class ImprovedList implements List{
	private final List list;
	public ImprovedList(List list){
		this.list = list;
	}
	public synchronized boolean putIfAbsent(T x){
		boolean contains = list.contains(x);
		if(!contains)
			list.add(x);
		return !contains;
	}
}

同期ポリシーのドキュメント化
ドキュメントには、お客様のコードについて理解する必要があるスレッドセキュリティ保証と、コード保守担当者が理解する必要がある同期ポリシーについて説明します.