2014-12-13 34 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