2014-12-13 35 views
1

这是我正在尝试做的。我有一些线程应该在一个共同的点上等待,然后才能继续,所以显而易见的解决方案是使用CyclicBarrier。但是我也想计算线程执行的总时间。我在类ConcurrentExecutionActionTimer中定义了以下实用方法。使用循环屏障不会等到所有线程完成

public static long elapsedTimeUsingCyclicBarrier(Executor executor, int concurrency, final Runnable action) throws InterruptedException 
     { 
      final Runnable barrierAction = new Runnable() { 
       @Override 
       public void run() { 
        System.out.println("Condition of barrier is met."); 
       } 
      }; 

      final 

CyclicBarrier barrier = new CyclicBarrier(concurrency, barrierAction); 
     final CountDownLatch done = new CountDownLatch(concurrency); 

     for(int i=0; i<concurrency; i++){ 
      executor.execute(new Runnable() { 
       @Override 
       public void run() { 
        try { 
         System.out.println("Waiting at barrier."); 
         barrier.await(); 
         action.run(); 
         //Cyclic barrier gets reset automatically. Again wait for them to finish. 
         barrier.await(); 
        } catch (InterruptedException e) { 
         Thread.currentThread().interrupt(); 
        } catch (BrokenBarrierException e) { 
         e.printStackTrace(); 
        } finally { 
         done.countDown(); 
        } 
       } 
      }); 
     } 
     long startNanoTime = System.nanoTime(); 
     done.await(); 
     return System.nanoTime() - startNanoTime; 
    } 

然后我把它叫做像:

public static void main(String[] args) { 
     //Executor is replacement for common thread idiom: (new Thread(r)).start() to e.execute(r) 
     ExecutorService executor = Executors.newFixedThreadPool(10); 
     Worker action = new Worker(); 
     int concurrency = 5; 
     try { 
     long elapsedTime = ConcurrentExecutionActionTimer.elapsedTimeUsingCyclicBarrier(executor, concurrency, action); 
     double seconds = (double)elapsedTime/1000000000.0; 
     System.out.println("Time Taken approximately: " + seconds + "seconds."); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
} 

这里Worker是假设我的线程做一些工作。例如:

class Worker implements Runnable { 
    @Override 
    public void run() { 
     System.out.println("Doing work."); 
     for(int i=0; i<20; i++) { 
      try { 
       Thread.sleep(500); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
     System.out.println("Finished."); 
    } 
} 

正如我想打印所花费的时间,我不得不使用CountDownLatch以确保所有线程都完成之前,控制不回回到主菜单。我们有其他方法来确保相同的功能吗?

回答

1

您应该使用相同的CyclicBarrier实例。唯一的区别是,您将循环屏障计数设置为#threads + 1.然后可以使用该屏障来计算完成所有线程所花费的时间。开始时间是在达到第一个屏障时计算的,并且在达到第二个屏障时计算结束时间。这样你就可以知道所有线程什么时候开始以及什么时候所有线程都完成了。

因此这样的:

long startNanoTime = System.nanoTime(); 
done.await(); 
return System.nanoTime() - startNanoTime; 

变为:

barrier.await() 
long startNanoTime = System.nanoTime(); 
barrier.await(); 
return System.nanoTime() - startNanoTime; 
+0

感谢克劳迪奥·科希。 – 2014-12-15 11:44:50