DarthVader
DarthVader

Reputation: 55122

Awaiting pool to finish threads

    StopWatch sw = new StopWatch();
    sw.start();
    ExecutorService executor = Executors.newFixedThreadPool(MYTHREADS);

    for (int i = 0; i < MYTHREADS; i++) {
        Runnable worker = new SingleConnectionRunnable();
        executor.execute(worker);
    }

    sw.stop();
    System.out.println("total time"+sw.toString());
    sw.reset();
    sw.start();

    for (int i = 0; i < MYTHREADS; i++) {
        Runnable worker2 = new PooledConnectionRunnable();
        executor.execute(worker2);
    }
    executor.shutdown();
    executor.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
    while (!executor.isTerminated()) {

    }

    sw.stop();
    System.out.println("total time"+sw.toString());

I am trying to run some perf tests on the code above. I am trying to use the same executor on different Runnable and measure the time. But it doesn't quite work. the first "total time" is not correct which is in milliseconds.

I want to print the elapsed time on the first loop then print the second loop. Not sure how I can wait executor to finish the first one then restart the executor.

What is the correct way to get this done?

Upvotes: 0

Views: 90

Answers (2)

user2982130
user2982130

Reputation:

First, awaitTermination will block until all tasks terminate. Is there any particular reason that you use a while loop check after waiting potentially 70 years?

Anyways, to answer your question, in order to wait for the first run to finish, you should use a CountDownLatch to signal completion of each thread and await for them in the main thread until they finish. You can also use a CyclicBarrier to await until all your threads are ready to go before starting timing, like so:

...
CountDownLatch latch = new CountDownLatch(MYTHREADS);
CyclicBarrier cb = new CyclicBarrier(MYTHREADS, new Runnable() {
    @Override public void run() {
        sw.start();
    }
});

for (...) {
    Runnable worker = ...
    executor.execute(new Runnable() {
        @Override public void run() {
            try { 
                cb.await(); 
            } catch (Exception e) { 
                throw new RuntimeException(e); 
            }

            worker.run();
            latch.countDown();
        }
    });
}

latch.await();
sw.stop();
...

I moved the sw.start() to the beginning of the for-loop to avoid measuring object allocation overhead to setup (probably won't be measured anyways since its in ms).

You can also reset the two concurrency classes to run an indefinite number of times.

Upvotes: 1

Totumus Maximus
Totumus Maximus

Reputation: 7583

What you are doing now is:

  1. Start the stopwatch
  2. Start a few threads
  3. Read the stopwatch

You are not waiting for them to finish like you do with the second loop.


This is what you can do to fix this.

Make a callback method in the SingleConnectionRunnable.

This method will be called at the last point of this runnable (when you terminate it) and caught by the class that starts the loop (which is not method in the question but that is fine).

In this callback method you keep track of how many times it is called.

When it is called MYTHREAD amount of times you print the stopwatch time.

Now you know how long it will take until all started threads are finished.

Upvotes: 0

Related Questions