バックタイマーCountDownLatchとループフェンス:CyclicBarrier

24302 ワード

一概念:1.マルチスレッドが連携して業務機能を完了する場合、他の複数のスレッドがタスクを完了するのを待ってから、メインスレッドが業務機能を実行し続ける必要がある場合があります.このような業務シーンでは、通常、Threadクラスのjoinメソッドを使用して、メインスレッドがjoinのスレッドによって実行されるのを待ってから、メインスレッドが実行され続けることができます.もちろん,スレッド間メッセージ通信メカニズムを用いてもよい.実はjavaコンカレントツールクラスには、「カウントダウン」のようなツールクラスが用意されており、このようなビジネスシーンを簡単に完成させることができます.
主な方法:
  • await()throws InterruptedException:このメソッドを呼び出すスレッドは、構築メソッドが入力したNが0に減少するまで実行されません.
  • await(long timeout,TimeUnit unit):上記のawaitメソッドと機能は一致しますが、ここでは時間制限があり、このメソッドを呼び出すスレッドは指定したtimeout時間まで待ってから、Nが0に減少するかどうかにかかわらず、
  • を実行し続けます.
  • countDown():CountDownLatchの初期値Nを1減少させる;
  • long getCount():現在のCountDownLatchメンテナンスの値を取得します.

  • 2.CountDownLatchを理解するために、一般的な例を挙げます.
    6人の選手と1人の審判がいて、選手は審判の銃声が鳴るのを待たなければ試合を開始できないと同時に、審判も選手の準備が終わってから試合を開始しなければならない.審判はゴール会でこの6人の選手のためにそれぞれ時間を計って、1人の選手がゴールに着いたとき、審判にとって1つの時間の任務が少なくなったことを想像することができる.すべての選手がゴールに着くまで、審判の任務も完成した.この6人の選手は6つのスレッドに類比することができる.
    public class CountDownLatchDemo {
    
    	private static CountDownLatch readySignal = new CountDownLatch(6);  //   6          
    	private static CountDownLatch startSignal = new CountDownLatch(1);  //         
    	private static CountDownLatch endSignal = new CountDownLatch(6);  //   6          
    
    	public static void main(String[] args) throws InterruptedException {
    		ExecutorService executorService = Executors.newFixedThreadPool(6);
    		for (int i = 0; i < 6; i++) {
    			executorService.execute(() -> {
    				try {
    					System.out.println(Thread.currentThread().getName() + "           !!!");
    					System.out.println(Thread.currentThread().getName() + "        !!!");
    					readySignal.countDown();
    					readySignal.await();
    					startSignal.await();
    					System.out.println(Thread.currentThread().getName() + "       ");
    					System.out.println(Thread.currentThread().getName() + "     ");
    					endSignal.countDown();
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    			});
    		}
    		readySignal.await();  //            
    		System.out.println("         !!!        !!!");
    		startSignal.countDown();
    		endSignal.await();
    		System.out.println("         ,    !");
    		executorService.shutdown();
    	}
    }
    

    実行結果:
    pool-1-thread-1           !!!
    pool-1-thread-2           !!!
    pool-1-thread-2        !!!
    pool-1-thread-3           !!!
    pool-1-thread-1        !!!
    pool-1-thread-3        !!!
    pool-1-thread-4           !!!
    pool-1-thread-4        !!!
    pool-1-thread-5           !!!
    pool-1-thread-5        !!!
    pool-1-thread-6           !!!
    pool-1-thread-6        !!!
             !!!        !!!
    pool-1-thread-6       
    pool-1-thread-4       
    pool-1-thread-6     
    pool-1-thread-5       
    pool-1-thread-5     
    pool-1-thread-3       
    pool-1-thread-1       
    pool-1-thread-1     
    pool-1-thread-2       
    pool-1-thread-2     
    pool-1-thread-3     
    pool-1-thread-4     
             ,    !
    
    Process finished with exit code 0
    
    

    二.ループフェンス:CyclicBarrier
    CyclicBarrierはマルチスレッド同時制御のユーティリティでもあり、CountDownLatchと同様にカウント待ち機能を備えていますが、CountDownLatchよりも強力です.
    CyclicBarrierの主な方法を見てみましょう.
  • await()throws InterruptedException,BrokenBarrierException//すべてのスレッドが指定された臨界点
  • に到達するまで待つ
  • await(long timeout,TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException//上記のawaitメソッド機能とほぼ一致するが、ここにはタイムアウト制限があり、タイムアウト時間に達するまでブロック待ち
  • int getNumberWaiting()/現在どれだけのスレッドブロックが臨界点で待機しているかを取得
  • boolean isBroken()/////ブロック待ちスレッドが中断されたかどうかを問い合わせる
  • //バリアを初期状態にリセットします.現在スレッドが臨界点で待機している場合は、BrokenBarrierExceptionが放出されます.void reset()はまた、CyclicBarrierがこのような構造方法を提供することに注意しなければならない.
    public CyclicBarrier(int parties, Runnable barrierAction)
    CyclicBarrierを使用すると、上記の要件も達成できます.
    public class CylicBarrierDemo {
    
    
    	public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
    
    		ExecutorService executorService = Executors.newFixedThreadPool(6);
    		CyclicBarrier barrier = new CyclicBarrier(6, () -> {
    			System.out.println("         !!!        !!!");
    		});
    
    		CyclicBarrier endBarrier = new CyclicBarrier(6, () -> {
    			System.out.println("         ,    !");
    		});
    
    		for (int i = 0; i < 6; i++) {
    			executorService.submit(()->{
    				try {
    					System.out.println(Thread.currentThread().getName() + "           !!!");
    					System.out.println(Thread.currentThread().getName() + "        !!!");
    					barrier.await();
    					System.out.println(Thread.currentThread().getName() + "       ");
    					System.out.println(Thread.currentThread().getName() + "     ");
    					endBarrier.await();
    				} catch (InterruptedException | BrokenBarrierException e) {
    					e.printStackTrace();
    				}
    			});
    		}
    	}
    }
    

    出力:
    pool-1-thread-1        !!!
    pool-1-thread-3           !!!
    pool-1-thread-3        !!!
    pool-1-thread-2           !!!
    pool-1-thread-2        !!!
    pool-1-thread-4           !!!
    pool-1-thread-4        !!!
    pool-1-thread-5           !!!
    pool-1-thread-5        !!!
    pool-1-thread-6           !!!
    pool-1-thread-6        !!!
             !!!        !!!
    pool-1-thread-6       
    pool-1-thread-6     
    pool-1-thread-1       
    pool-1-thread-1     
    pool-1-thread-2       
    pool-1-thread-2     
    pool-1-thread-5       
    pool-1-thread-5     
    pool-1-thread-4       
    pool-1-thread-4     
    pool-1-thread-3       
    pool-1-thread-3     
             ,    !