Java concurrency in practice読書ノート---synchronizer同期ツール類

5238 ワード

コンテナクラスでは、ブロッキングキューは、takeメソッドとputメソッドがキューが所望の状態に達するまで(キューが空でも満でもない)ブロッキングされるため、保存対象のコンテナとして機能するだけでなく、生産者と消費者などのスレッド間の制御フローを調整するユニークなクラスです.
同期ツールクラスは、スレッドの制御フローが自身のステータスに基づいて調整される限り、任意のオブジェクトであってもよい.ブロッキングキューは、同期ツールクラスとして使用できます.他のタイプの同期ツールクラスには、信号量(Semaphore)、フェンス(Barrier)、およびロック(Latch)も含まれます.これらのクラスがまだ必要に応じていない場合は、独自の同期ツールクラスを作成できます.
すべての同期ツールクラスには、特定の構造化プロパティが含まれています.これらのプロパティには、同期ツールクラスを実行するスレッドが実行を続行するか待機するかを決定するステータスがカプセル化されています.また、ステータスを操作する方法や、同期ツールクラスが予想される状態に入るのを効率的に待つ方法もあります.
Latch
Latchは1つのgateに相当し、Latchが特定の状態に達する前にgateがオフになると、すべてのスレッドがブロックされ、Latchが特定の状態に達してこそ、スレッドがgateを通過することができる.
CountDownLatchはLatchの具体的な実装であり、CountDownLatchの内部にはカウンタが維持されており、CountDownLatchを初期化するにはカウンタの初期値を指定する必要がある.この初期値は、完了を待つ必要があるイベントの数を表します.countDouwnメソッドが呼び出されるたびに、カウンタの値が1つのイベントが完了することを示します.カウンタが0に減少すると、gateは開きます.
public class TestHarness {
	/**
	 *   nThreads       task     
	 */
	public long timeTasks(int nThreads, final Runnable task) throws InterruptedException {
		final CountDownLatch startGate = new CountDownLatch(1);
		final CountDownLatch endGate = new CountDownLatch(nThreads);

		for (int i = 0; i < nThreads; i++) {
			Thread t = new Thread() {
				public void run() {
					try {
						//   startGate       0    await   
						startGate.await();
						try {
							task.run();
						} finally {
							//          endGate 1
							endGate.countDown();
						}
					} catch (InterruptedException ignored) {
					}
				}
			};
			t.start();
		}

		long start = System.nanoTime();
		//  startGate       1,   startGate
		startGate.countDown();
		//   endGate       0    await   
		endGate.await();
		long end = System.nanoTime();
		return end - start;
	}
}

FutureTask
FutureTaskはタスクを実行するために使用され、getメソッドはタスクの実行結果を返します.FutureTaskでよく使われるコンストラクション関数はFutureTaskです(Callablecallable)は、Callableを使用してタスクをカプセル化します.FutureTaskオブジェクトには、実行待ち、実行中、完了の3つの状態があります.FutureTaskオブジェクトが完了状態にある場合にgetメソッドを呼び出すと、getメソッドはすぐに計算結果を返します.そうしないと、getメソッドはブロックされ、FutureTaskが完了状態に遷移したことがわかります.計算が完了、例外が放出されたり、キャンセルされたりします.FutureTaskの状態を完了にします.FutureTaskの一般的な使用シーンは、時間のかかるタスクをカプセル化し、計算を事前に開始し、結果を計算する必要がある場合にgetメソッドを呼び出すことで、計算の完了を待つ時間を短縮できます.
FutureTaskの使用例:
public class Preloader {
	private final FutureTask<ProductInfo> future = new FutureTask<ProductInfo>(new Callable<ProductInfo>() {
		public ProductInfo call() throws DataLoadException {
			// loadProductInfo          ,         
			return loadProductInfo();
		}
	});
	// FutureTask   Runnable  ,      future    thread   
	private final Thread thread = new Thread(future);

	//   start      ,                   this  
	public void start() {
		//   thread,   future
		thread.start();
	}

	//         ,    get             . 
	public ProductInfo get() throws DataLoadException, InterruptedException {
		try {
			// get     ,           ,       
			return future.get();
		} catch (ExecutionException e) {
			Throwable cause = e.getCause();
			if (cause instanceof DataLoadException)
				throw (DataLoadException) cause;
			else
				throw launderThrowable(cause);
		}
	}
	
	public static RuntimeException launderThrowable(Throwable t) { 
	    if (t instanceof RuntimeException) 
	        return (RuntimeException) t; 
	    else if (t instanceof Error) 
	        throw (Error) t; 
	    else 
	        throw new IllegalStateException("Not unchecked", t); 
	}
} 

Semaphore--信号量
Semaphoreはpermitを管理するために使用され、Semaphoreオブジェクトを作成する場合、permitの最大個数を指定する必要があります.acquire()メソッドを呼び出してSemaphoreオブジェクトからpermitを取得します.現在のSemaphoreオブジェクトに使用可能なpermitがない場合、スレッドはブロックされ、使用可能なpermitがあることがわかり、release()メソッドを呼び出してpermitをSemaphoreオブジェクトに戻します.permitはスレッドにバインドされず、1つのスレッドが申請したpermitは、別のスレッドでreleaseすることができます.Semaphoreは、通常、データベース接続プールなどのリソースプールを実装するために使用されます.Semaphoreはまた、境界のある集合を実現するために使用することもできる.次のようになります.
/**
 *    set  
 */
public class BoundedHashSet<T> { 
    private final Set<T> set; 
    private final Semaphore sem; 

    public BoundedHashSet(int bound) { 
        this.set = Collections.synchronizedSet(new HashSet<T>()); 
        //   Semaphore    permit     
        sem = new Semaphore(bound); 
    } 

    public boolean add(T o) throws InterruptedException { 
    	//   add   semaphore      permit
        sem.acquire(); 
        boolean wasAdded = false; 
        try { 
            wasAdded = set.add(o); 
            return wasAdded; 
        } 
        finally { 
            if (!wasAdded) 
            	//       release permit
                sem.release(); 
        } 
    } 

    public boolean remove(Object o) { 
        boolean wasRemoved = set.remove(o); 
        if (wasRemoved) 
        	//       permit release
            sem.release(); 
        return wasRemoved; 
    } 
}

CyclicBarrier
CyclicBarrierは、スレッドのセットが共通のバリアポイントにすべて到達まで互いに待つことを可能にする.CyclicBarrierを作成するには、スレッドグループ内のスレッドの数を指定する必要があります.CyclicBarrierオブジェクトのawaitメソッドを呼び出し、現在のスレッドが共通のバリアポイントに到達し、他のスレッドの到着を待つことを示す.すべてのスレッドが共通のバリアポイントに到達と、CyclicBarrierオブジェクトはスレッドグループを解放し、CyclicBarrierオブジェクトの状態をリセットする.したがってCyclicBarrierオブジェクトはリサイクル可能である.待機中にスレッドがタイムアウトまたは中断する場合、CyclicBarrierオブジェクトは破損しているとみなされ、awaitメソッドの呼び出しはBrokenBarrierException異常を放出する.