Java - 基于时间步长同步多个线程

时间:2012-07-22 17:45:41

标签: java multithreading

假设我有一个Master,它保存SlaveThread对象的列表。在每个时间步,我希望Master并行运行SlaveThreads,但是,在时间步的结束时,我希望SlaveThreads在向前推进之前等待彼此完成当前时间步。另外,我不想在每个时间步重新实现SlaveThreads。我有两个可能的解决方案,我不知道如何使它们中的任何一个工作:

1)SlaveThread中的run()方法处于while(true)循环中。在SlaveThread中执行单个循环之后,我将让SlaveThread通知Master(我不知道该怎么做),而Master会做类似的事情

try{
    for (int i = 0; i < numSlaveThreads; i++) {
        while (!slaveThreads[i].getCompletedThisIter()) {
        wait()
        }
      }
  System.out.println("Joined");

}

在进入下一个时间步之前。我该怎么做?如何让一个SlaveThread只通知主服务器?

2)Slave中的run()不在while(true)循环中,然后我必须在每次迭代时调用start()。但是此时Slave的线程状态将被终止。如何在不重新实例化的情况下再次调用start()?

2 个答案:

答案 0 :(得分:5)

这正是障碍的所在,您可以通过CyclicBarrierCountDownLatch实现这一目标。这些是同步器,用于延迟线程的进度,直到达到所需的状态,在这种情况下,线程已完成计算。

这取决于你想要实现的细节:

  

锁存器用于等待事件;障碍是等待其他的   线程。

对于以下列方式完成的CyclicBarrier

// whereby count is the number of your slave threads
this.barrier = new CyclicBarrier(count); 

然后在您的奴隶的Runnable定义中,您将在计算结束时插入:barrier.await()

public class Slaves implements Runnable {

   // ...

   @Override
   public void run() {

      while(condition) {

         // computation
         // ...

         try {
            // do not proceed, until all [count] threads
            // have reached this position
            barrier.await();
         } catch (InterruptedException ex) {
            return;
         } catch (BrokenBarrierException ex) {
            return;
         }
      }
   }
}

在所有线程完成计算之前,您的从属线程将不会继续。这样您就不需要在另一个主线程之间实现信令。

但是,如果您想要在所有线程到达该位置(主信令)后执行某些代码,则可以将另外的Runnable传递给CyclicBarrier构造函数,该构造函数将在执行之后执行所有线程都到达了障碍。

this.barrier = new CyclicBarrier(count,
   new Runnable() {
      @Override
      public void run() {
         // signal your master thread, update values, etc.
      }
    }
 );

答案 1 :(得分:3)

您可以使用ExecutorService的组合来管理您的线程(即,您可以回收线程而无需在每个周期创建新线程)和CyclicBarrier来同步所有从属。< / p>

请参阅下面的一个简单示例,其中主服务器在循环中启动从服务器,确保它们在重新启动之前完成所有操作。奴隶,有点懒,只是睡觉一些(不是真正的随机)时间:

public class Test {

    private static final ExecutorService executor = Executors.newFixedThreadPool(5);
    private static final CyclicBarrier barrier = new CyclicBarrier(5); //4 slaves + 1 master

    public static void main(String[] args) throws InterruptedException {
        Runnable master = new Runnable() {
            @Override
            public void run() {
                try {
                    while (true) {
                        System.out.println("Starting slaves");
                        for (int i = 100; i < 500; i += 100) {
                            executor.submit(getRunnable(i));
                        }
                        barrier.await();
                        System.out.println("All slaves done");
                    }
                } catch (InterruptedException | BrokenBarrierException ex) {
                    System.out.println("Bye Bye");
                }
            }
        };

        executor.submit(master);
        Thread.sleep(2000);
        executor.shutdownNow();

    }

    public static Runnable getRunnable(final int sleepTime) {
        return new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("Entering thread " + Thread.currentThread() + " for " + sleepTime + " ms.");
                    Thread.sleep(sleepTime);
                    System.out.println("Exiting thread " + Thread.currentThread());
                    barrier.await();
                } catch (BrokenBarrierException | InterruptedException ex) {
                }
            }
        };

    }
}