JAva同期のCountDownLatch、CyclicBarrier
7965 ワード
JAva apiは多くのスレッド同期に関するクラスとインタフェースを提供し、すべてのソースコードはjava.util.concurrentというパッケージの中にあり、主な原子のクラスとスレッドの安全な集合フレームワーク、そして重要なロックの実現、ロックの実現はjucのlocksというパッケージの中で、本節はロックの実現を論じず、主にjucの下のCountDownLatchとCyclicBarrierを説明し、使用する.
CountDownLatch ソース解釈
他のスレッドで実行されている一連の操作を完了する前に、1つ以上のスレッドを待機させる同期支援クラス.
与えられたカウントで
CyclicBarrier ソース解釈
共通のバリアポイント(common barrier point)に達するまでスレッドのセットを互いに待つことができる同期支援クラス.一定サイズのスレッドのセットに関連するプログラムでは、これらのスレッドは常に互いに待たなければならない.この場合、CyclicBarrierは有用である.このbarrierは、待機スレッドを解放した後に再利用できるため、ループのbarrierと呼ばれる.
CyclicBarrierは、1組のスレッドの最後のスレッドが到着した後(ただし、すべてのスレッドを解放する前に)、各バリアポイントでのみ実行されるオプションのRunnableコマンドをサポートします.すべての参加スレッドを続行する前に共有ステータスを更新すると
apiのこの2つのクラスの説明から、この2つのクラスは同期補助クラスであり、この2つのクラスはいくつかの類似点がバリアポイントを提供している.すなわち、スレッドはバリアポイントに達する前に待機し、CountDownLatchの役割は、1またはNのスレッドが他のスレッドが実行を完了するのを待つことを許可することである.CyclicBarrierはN個のスレッドが互いに待つことを許可する.CountDownLatchのカウンタはリセットできません.CyclicBarrierのカウンタはリセットして使用できるので、ループのbarrieと呼ばれています.
次の2つのクラスの使用例は、1つの大きなワークをいくつかの小さなワークに分けて実行し、最後に合計を計算することです.この例は5億回のプラス1操作を計算し、それぞれCountDownLatchとCyclicBarrierで実現し、コード部分を直接貼り付けます.
/** * Test 2.java Create on 2014年10月9日 * * Copyright(c)2014年10月9日by dzh* * @author xingyu * @version 0.0.1* */package org.dzh.lock;import java.util.ArrayList;import java.util.List;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CountDownLatch;import java.util.concurrent.CyclicBarrier;/**@className:Test2.java * @description:セグメント計算5億回の+1 * @date 2014年10月9日午前10:29:29 */public class Test2 { private static List result = new ArrayList<>(); /**@className:Test2.java * @description:CountDownLatch実装計算 * @date 2014年10月9日午前10:30:08 */ public static class CDL implements Runnable{ private final CountDownLatch startSignal; private final CountDownLatch doneSignal; CDL(CountDownLatch startSignal,CountDownLatch doneSignal){ this.startSignal = startSignal; this.doneSignal = doneSignal; } @Override public void run() { try { this.startSignal.await(); doWork(); this.doneSignal.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } } void doWork(){ System.out.println("現在のスレッドの名前は:"+Thread.currentThread().getName(); } } public static void mainCDL() throws InterruptedException{ CountDownLatch startSignal=new CountDownLatch(1);//すべてのスレッドが準備されてから作業を開始 CountDownLatch doneSignal=new CountDownLatch(5);//すべてのスレッドの演算が終了し、作業開始 for (int i = 0; i < 5; i++) { new Thread(new CDL(startSignal,doneSignal),"スレッド"+i).start(); } dosomethingElse(); startSignal.contDown();//startSignalカウントが1つ減少したことは、startSignal.awaitがアクティブになって動作を開始することを意味する System.out.println(「現在の数:」+startSignal.getCount(); dosomethingElse(); doneSignal.await();//doneSignalカウントが0になるまで待つ System.out.println(「終了するかどうか!」); } public static class CDL2 implements Runnable{ private final CountDownLatch cdl; private int startIndex; private int endIndex; CDL2(CountDownLatch cdl,int startIndex,int endIndex){ this.cdl = cdl; this.startIndex = startIndex; this.endIndex = endIndex; } @Override public void run() { int num = 0; for (int i = startIndex; i < endIndex; i++) { num +=1; } result.add(num); cdl.countDown(); } } public static void mainCDL2(){ long startTime = System.currentTimeMillis(); CountDownLatch cdl = new CountDownLatch(5); try { result.clear(); int index = 100000000; for (int i = 1; i <=5; i++) { int num = index*i; new Thread(new CDL2(cdl, num-index, num)).start();; } cdl.await(); sum(); System.out.println(「計算時間:」+(System.currentTimeMillis)-startTime); } catch (InterruptedException e) { e.printStackTrace(); } } /**@className:Test2.java * @description:CyclicBarrier実装計算 * @date 2014年10月9日午前10:31:03 */ public static class CB{ int N; final CyclicBarrier cb; class Worker implements Runnable{ int myRows; Worker(int row){ this.myRows = row; } @Override public void run() { System.out.println(myRows+「現在のスレッド計算終了:」+Thread.currentThread().getName(); try { cb.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } } CB(){ cb = new CyclicBarrier(5, new Runnable() { @Override public void run() { System.out.println("現在のスレッドは:"+Thread.currentThread().getName(); System.out.println(「計算の合計:」+1000); } }); for (int i = 0; i < 5; i++) { new Thread(new Worker(i)).start(); } } } public static void main(String[] args) throws InterruptedException{ //mainCDL(); // for (int i = 0; i < 10; i++) {// mainCDL2();// new Test().cal();// } new CB(); } static void dosomethingElse(){ System.out.println(「何をしようか!」); } static void sum(){ int sum = 0; for (int i = 0; i < result.size(); i++) { sum += result.get(i); } System.out.println(「計算合計:」+sum); }}
CountDownLatch ソース解釈
他のスレッドで実行されている一連の操作を完了する前に、1つ以上のスレッドを待機させる同期支援クラス.
与えられたカウントで
CountDownLatch
を初期化する.countDown()メソッドが呼び出されるため、awaitメソッドは、現在のカウントがゼロに達するまでブロックされ続けます.その後、待機中のすべてのスレッドが解放され、awaitの後続の呼び出しはすぐに返されます.この現象は1回しか現れません.カウントはリセットできません.カウントをリセットする必要がある場合は、CyclicBarrierを使用することを考慮してください.CountDownLatch
は汎用同期ツールであり、多くの用途があります.カウント1を初期化したCountDownLatch
は、単純なオン/オフラッチとして使用されるか、または、countDown()を呼び出すスレッドによってエントリが開く前に、awaitを呼び出すすべてのスレッドが入口で待機している.Nによって初期化されたCountDownLatch
は、1つのスレッドをN個のスレッドがある動作を完了するまで待機させるか、またはある動作がN回完了するまで待機させることができる. CountDownLatch
の有用な特性は、countDown
メソッドを呼び出すスレッドがカウントがゼロに達するまで継続することを要求しないことであり、すべてのスレッドが通過する前に、awaitを通過することを阻止するだけである.CyclicBarrier ソース解釈
共通のバリアポイント(common barrier point)に達するまでスレッドのセットを互いに待つことができる同期支援クラス.一定サイズのスレッドのセットに関連するプログラムでは、これらのスレッドは常に互いに待たなければならない.この場合、CyclicBarrierは有用である.このbarrierは、待機スレッドを解放した後に再利用できるため、ループのbarrierと呼ばれる.
CyclicBarrierは、1組のスレッドの最後のスレッドが到着した後(ただし、すべてのスレッドを解放する前に)、各バリアポイントでのみ実行されるオプションのRunnableコマンドをサポートします.すべての参加スレッドを続行する前に共有ステータスを更新すると
apiのこの2つのクラスの説明から、この2つのクラスは同期補助クラスであり、この2つのクラスはいくつかの類似点がバリアポイントを提供している.すなわち、スレッドはバリアポイントに達する前に待機し、CountDownLatchの役割は、1またはNのスレッドが他のスレッドが実行を完了するのを待つことを許可することである.CyclicBarrierはN個のスレッドが互いに待つことを許可する.CountDownLatchのカウンタはリセットできません.CyclicBarrierのカウンタはリセットして使用できるので、ループのbarrieと呼ばれています.
次の2つのクラスの使用例は、1つの大きなワークをいくつかの小さなワークに分けて実行し、最後に合計を計算することです.この例は5億回のプラス1操作を計算し、それぞれCountDownLatchとCyclicBarrierで実現し、コード部分を直接貼り付けます.
/** * Test 2.java Create on 2014年10月9日 * * Copyright(c)2014年10月9日by dzh* * @author xingyu * @version 0.0.1* */package org.dzh.lock;import java.util.ArrayList;import java.util.List;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CountDownLatch;import java.util.concurrent.CyclicBarrier;/**@className:Test2.java * @description:セグメント計算5億回の+1 * @date 2014年10月9日午前10:29:29 */public class Test2 { private static List