同時(5)-concurrentパッケージコンポーネント

3742 ワード

java.util.concurrentのコンポーネント


CountDownLatch

CountDownLatchは、1つまたは複数のタスクを同期させ、タスクのセットの動作を強制するために使用される.
public class Main {
   static final int SIZE = 10;

   public static void main(String[] args) throws InterruptedException, IOException {

       ExecutorService exec = Executors.newCachedThreadPool();
       CountDownLatch latch = new CountDownLatch(SIZE);
       int count = 10;
       while (count-- > 0) {
           exec.execute(() -> {
               try {
                   TimeUnit.MILLISECONDS.sleep(100);
                   System.out.println("one task was finished");
               } catch (InterruptedException e) {
                   e.printStackTrace();
               } finally {
                   latch.countDown();
               }
           });
       }
       exec.execute(() -> {
           try {
               latch.await();
               System.out.println("submit tasks report");
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       });
       TimeUnit.MILLISECONDS.sleep(4000);
       exec.shutdownNow();
   }

}

one task was finished one task was finished one task was finished one task was finished one task was finished one task was finished one task was finished one task was finished one task was finished one task was finished submit tasks report CountDownLatchオブジェクト上でawait()メソッドを呼び出すタスクは、latchカウントが0になるまでブロックされます.CountDownLatchは、一度しか使用できず、カウンタの値をリセットできないように設計されている.

CyclicBarrier


複数回再利用可能なCountDownLatch.
public class Main {

   private static final int SIZE = 10;
   private static Random random = new Random(47);

   public static void main(String[] args) throws InterruptedException, IOException {

       ExecutorService exec = Executors.newCachedThreadPool();
       CyclicBarrier barrier = new CyclicBarrier(SIZE, () -> System.out.println("submit tasks report"));
       int count = 10;
       while (count-- > 0){
           exec.execute(() -> {
               try {
                   TimeUnit.MILLISECONDS.sleep(random.nextInt(1000));
                   System.out.println("one task was finished");
                   barrier.await();
               } catch (InterruptedException | BrokenBarrierException e) {
                   e.printStackTrace();
               }
           });
       }
       TimeUnit.MILLISECONDS.sleep(4000);
       exec.shutdownNow();
   }

}
CyclicBarrierオブジェクトが呼び出されたawait()回数、すなわち、このリソースを待ってブロックされたスレッド数が、このコンストラクタに設定された値に達すると、コンストラクタに入力されたRunnable()メソッドが実行され、count値を20に変更すると、この「submit tasks report」が2回出力され、すなわち、我々が望む効果を達成することができる.

ScheduledExecutor

schedule()(タスクを1回実行)またはscheduleAtFixedRate()(ルールごとにタスクを繰り返し実行)を使用します.
public class Main {

    private static final int SIZE = 5;
    private static Random random = new Random(47);

    public static void main(String[] args) throws InterruptedException, IOException {
        long start = System.currentTimeMillis();
        ScheduledExecutorService service = Executors.newScheduledThreadPool(SIZE);
        for (int i = 0; i < SIZE; i++) {
            service.schedule(() -> System.out.println(System.currentTimeMillis() - start),
                    random.nextInt(3000), TimeUnit.MILLISECONDS);
        }
        TimeUnit.SECONDS.sleep(5);
        service.shutdownNow();
    }
}
ScheduledExecutorを使用してTimerと区別されるのは、Timerがこのタスクを実行するために新しいスレッドを作成しないことであり、以前のタスクの実行時間が次のタスクとの間隔より大きくなり、次のタスクが遅延する可能性があります.