如何正确使用CyclicBarrier的循环行为来完成两组不同的任务?

时间:2018-01-24 20:21:42

标签: java multithreading concurrency synchronization

CyclicBarrier在最后一个线程进入屏障时执行屏障操作。

如果在CyclicBarrier中定义了5个派对(线程),那么当第5个线程(任务)进入屏障时,屏障将跳闸(即将重置)并且屏障操作将被执行。

这里,第五个线程是什么类型并不重要。这可能是任何任务。

所以,我的问题是:

  1. 如果有两组任务(每个5个线程),那么如何确保首先执行一组特定的任务,然后执行barrier action命令。 剩下的一组任务在此之后执行,然后再次执行barrier action命令。

  2. CyclicBarrier是否适合这些场景。 如果没有,那么它的循环行为如何在现实场景中正确使用。

  3. 以下是CyclicBarrier代码。

    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;
    
    
    public class CyclicBarrierSimpleExample {
        static int barrierActionThreadCount;
        public static void main(String[] args){
            // 5 is the number of parties. So, when the 5th thread will enter the barrier, barrier gets tripped or reset and BarrierAction will be called. 
            final CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new BarrierAction(barrierActionThreadCount));
    
            for(int i=0;i<5;i++){
                Thread validationTask = new Thread(new ValidationTask(i, cyclicBarrier));
                validationTask.start();
            }
    
            for(int i=0;i<5;i++){
                Thread serviceTask = new Thread(new ServiceTask(i, cyclicBarrier));
                serviceTask.start();
            }
        }
    }
    
    class BarrierAction implements Runnable{
        private int barrierActionThreadCount;
        public BarrierAction(int barrierActionThreadCount) {
            this.barrierActionThreadCount=barrierActionThreadCount;
        }
        // Barrier action will execute when barrier is reached i.e. number of parties waiting got executed
        // In this case, it will trip when 5 different threaValidationTaskds are called and then again its number of parties will reset to 5
        @Override
        public void run() {
            this.barrierActionThreadCount++;
            System.out.println("Barrier action thread got executed "+barrierActionThreadCount+" times");
        }
    
    }
    
    
    class ValidationTask implements Runnable{
        CyclicBarrier cyclicBarrier; 
        int threadNum;
        public ValidationTask(int threadNum, CyclicBarrier cyclicBarrier) {
            this.threadNum = threadNum;
            this.cyclicBarrier = cyclicBarrier;
        }
        @Override
        public void run() {
            try {
                Thread.sleep(threadNum*1000);
            } catch (InterruptedException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            System.out.println("Validation Task: Thread-"+threadNum+" got executed");
            try {
    
                cyclicBarrier.await();
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
    
        }
    
    }
    
    class ServiceTask implements Runnable{
        CyclicBarrier cyclicBarrier; 
        int threadNum;
        public ServiceTask(int threadNum, CyclicBarrier cyclicBarrier) {
            this.threadNum = threadNum;
            this.cyclicBarrier = cyclicBarrier;
        }
        @Override
        public void run() {
            System.out.println("Service Task: Thread-"+threadNum+" got executed");
            try {
                cyclicBarrier.await();
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
    
        }
    
    }
    

    上述任务的输出:

    Validation Task: Thread-0 got executed
    Service Task: Thread-1 got executed
    Service Task: Thread-0 got executed
    Service Task: Thread-4 got executed
    Service Task: Thread-2 got executed
    Service Task: Thread-3 got executed
    Barrier action thread got executed 1 times
    Validation Task: Thread-1 got executed
    Validation Task: Thread-2 got executed
    Validation Task: Thread-3 got executed
    Validation Task: Thread-4 got executed
    Barrier action thread got executed 2 times
    

    我期望的行为是首先执行所有验证任务,然后执行服务任务。

    感谢您的帮助。

2 个答案:

答案 0 :(得分:3)

您不使用大小为5的障碍来控制10个线程。

使用大小为5的屏障来控制5个线程,其中每个线程执行一系列操作,等待所有线程完成一个步骤,然后继续下一步。

如果要启动10个线程,并让5个ServiceTask个线程等待5 ValidationTask个线程完成,请使用CountDownLatch,将其同时提供给{{1} }和ValidationTask

ServiceTask应该在开始时调用ServiceTaskawait​()应该在结束时调用ValidationTask

这样在所有countDown​()完成之前就没有ServiceTask运行,并且ValidationTask可以在完成后立即单独停止,而不是所有人都必须先等待停止。

答案 1 :(得分:2)

第一个问题的答案: 正如Andreas提到的,CountDownlatch可用于您提到的方案。

第二个问题的答案: 下面是使用CyclicBarrier的循环行为的代码。

在此示例中,有5个线程正在使用CyclicBarrier并多次调用await()方法以到达并在多个检查点同时等待。

 package dev.cyclicbarrier;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBehaviorDemo {

    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(5, new Runnable() {

            public void run() {
                System.out.println("All threads Arrived at barrier Checkpoint");
            }

        });

        Thread t1= new Thread(new Task(barrier),"thread-1");
        Thread t2= new Thread(new Task(barrier),"thread-2");
        Thread t3= new Thread(new Task(barrier),"thread-3");
        Thread t4= new Thread(new Task(barrier),"thread-4");
        Thread t5= new Thread(new Task(barrier),"thread-5");

        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }

}

class Task implements Runnable {
    CyclicBarrier barrier;

    Task(CyclicBarrier barrier) {
        this.barrier = barrier;
    }

    public void run() {
        try {
            System.out.println(Thread.currentThread().getName() + " has started for checkpoint 1");
            barrier.await();

            System.out.println(Thread.currentThread().getName() + " has started for checkpoint 2");
            barrier.await();

            System.out.println(Thread.currentThread().getName() + " has started for checkpoint 3");
            barrier.await();

            System.out.println(Thread.currentThread().getName() + "has finished");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }

}

以上程序的输出为

    thread-2 has started for checkpoint 1
    thread-4 has started for checkpoint 1
    thread-1 has started for checkpoint 1
    thread-3 has started for checkpoint 1
    thread-5 has started for checkpoint 1
    All threads Arrived at barrier Checkpoint
    thread-2 has started for checkpoint 2
    thread-4 has started for checkpoint 2
    thread-5 has started for checkpoint 2
    thread-1 has started for checkpoint 2
    thread-3 has started for checkpoint 2
    All threads Arrived at barrier Checkpoint
    thread-3 has started for checkpoint 3
    thread-2 has started for checkpoint 3
    thread-4 has started for checkpoint 3
    thread-5 has started for checkpoint 3
    thread-1 has started for checkpoint 3
    All threads Arrived at barrier Checkpoint
    thread-1has finished
    thread-3has finished
    thread-2has finished
    thread-4has finished
    thread-5has finished