Here is what I am trying to do. I have a number of threads which should all wait at a common point before they proceed, so obvious solution is to use CyclicBarrier
. But I want to also compute the total time taken by the threads to execute. I defined the following utility method in class 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;
}
Then I called it up like:
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();
}
}
Here Worker
is suppose my thread that does some work. For example:
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.");
}
}
As I wanted to print the time taken I had to use CountDownLatch
to make sure the control does not return back to main before all the threads are finished. Do we have any other way to make sure the same functionality?
You should use the same CyclicBarrier instance. The only difference is that you make the cyclic barrier count be #threads + 1. You can then use that barrier to calculate the time it took all of the threads to complete. The start time is calculated when the first barrier has been reached and the end time is calculated when the second barrier has been reached. This way you know approximately when all the threads have been started and when all of them have completed.
Therefore this:
long startNanoTime = System.nanoTime();
done.await();
return System.nanoTime() - startNanoTime;
becomes:
barrier.await()
long startNanoTime = System.nanoTime();
barrier.await();
return System.nanoTime() - startNanoTime;