ExecutorService与Runnable共享CyclicBarrier

时间:2014-05-09 11:28:58

标签: java multithreading executorservice cyclicbarrier

我在Java的并发解决方案中遇到问题,使用共享CyclicBarrier的n Runnable类,而RunnableExecutorService处理,这是代码:

public class Worker implements Runnable {
   private CyclicBarrier writeBarrier;
   private int index;
   private int valuetocalculate;

   public Worker(int i,CyclicBarrier writeBarrier)
   {
      this.writeBarrier = writeBarrier;
      this.index = i;
      this.valuetocalculate = 0;
   }

   public void run() {

      //calculations with valuetocalculate
      writeBarrier.await();
      //write new valuetocalculate value
   }
}

public class Context {

    private ArrayList<Worker> workers;
    private Chief chief;

    public Context()
    {
       workers = new ArrayList<Worker>();
       chief = new Chief();
    }

    public void generateRandomWorkers(nworkers)
    {
       writeBarrier = newWriteBarrier(workers);
       chief.setBarrier(writeBarrier);
       //generate random woker
       for (int i = 0; i<nworkers;i++)
       {
           Worker worker = new Worker(i,writeBarrier);
           workers.add(worker);
       }
       chief.setWorkersArray(workers);
       chief.start();
     }
}

public class Chief extend Thread {

    private CyclicBarrier writeBarrier;
    private ArrayList<Worker> workers;
    private ExecutorService executor;
    private int cores;

    public Chief ()
    {
       cores = Runtime.getRuntime().availableProcessors()+1;
    }

    public void setBarrier (CyclicBarrier writeBarrier)
    {
       this.writeBarrier = writeBarrier;
    }

    public setWorkersArray(ArrayList<Worker> workers)
    {
       this.workers = workers;
    }

    public ArrayList<Integer> getvaluetocalculate()
    {
        ArrayList<Integer> values = new ArrayList<Integer> ();
        for (int i = 0; i<workers.size();i++)
        {
           values.add(workers.get(i).valuetocalculate);
        }

         return values;
    }

    public void run(){
       while (!stop) //always true for testing
       {
          getvaluetocalculate();
          //make calculations
          writeBarrier.reset();
          executor = Executors.newFixedThreadPool(cores);
          for (int i = 0;i<workers.size();i++)
          {
             Runnable runnable = workers.get(i);
             executor.execute(runnable);
           }
           executor.shutdown();
           while (!executor.isTerminated())
           {
           }
        }
     }
}

所有内容始于主要内容:

Context = new Context();
context.generateRandomWorkers();

问题是Runnable没有超过Chief运行中的第一个“迭代”,所以似乎问题是工人没有超过writerBarrier.await(); {1}},相反,如果我初始化了这个:

executor = Executors.newFixedThreadPool(cores);

workers.size()一起工作,但似乎没有同步......我怎么解决?

1 个答案:

答案 0 :(得分:0)

好的,所以看起来你正在尝试执行以下操作

  • 一个控制工人的主管/调度员
  • 一名或多名工人正在进行计算
  • Chief执行所有工人
  • 酋长等待所有工人完成
  • Chief获取每个工人的结果以计算结果

假设上面是你的问题。

  • 在worker run()方法中执行barrier.await()可防止该线程被释放回池中以运行后续worker。因此,当池大小<1时工人规模第一个游泳池大小&#39;工人消耗线程然后停止等待其他无法运行的线程。这就是为什么除非您将池大小更改为workers.size()。
  • ,否则不会运行所有工作程序
  • valuetocalculate变量在设置结果的工作人员和读取结果的主人之间未同步,因此您可能会看到陈旧的结果。

实现此类系统的正确方法是让worker实现Callable,其中callable在worker计算后返回结果。这需要将结果发布给您的主管(您将在下面看到它的工作原理)。

移除循环屏障,您不需要。

像现在一样创建执行程序,并使用Callables列表(您的工作人员)调用invokeAll()。此方法使用执行程序调用Callables并等待它们完成。它会阻塞,直到所有工人完成,此时它将返回List<Future<T>>。每个Future对应于您传入的一个worker / Callables。迭代列表拉出结果。如果某个工作人员未能尝试get() Future,{{1}}会导致异常。

希望有所帮助。