How to calculate the total time it takes for multiple threads to finish executing?
Asked Answered
I

6

5

I am starting multiple threads(around 1000) from my code. They are Runnable threads called from a while loop. How do I calculate the total time taken for all threads to finish executing?

Also I am opening a DB Connection and have a set of queries for which I am starting these threads(1 thread for 1 query). When do I close the connection?

Incommensurable answered 8/8, 2012 at 7:17 Comment(0)
A
8

I would use an ExecutorService

long start = System.nanoTime();
ExecutorService service = Executors.newWhatEverPool();
for(loop)
   service.submit(new MyRunnable());

service.shutdown();
service.awaitTermination(1, TimeUnit.HOUR); // or longer.    
long time = System.nanoTime() - start;
System.out.printf("Tasks took %.3f ms to run%n", time/1e6);

Close the connection when you have finished with it. It is a common pattern for the creator of a resource to also close it. e.g. If the main thread creates the connection, it could close after all the threads have finished.

Argil answered 8/8, 2012 at 7:26 Comment(11)
of course this had the limitation that if these Threads take more then 1 hour to execute..Narva
+1 for the ExecutorService which is a very convenient way for executing threads!Meed
@Narva Which is why you can make it "longer" like 100000, TimeUnits.DAYS ;)Argil
Executors.newWhatEverPool(); - which thread pool should we use? New to threads. Sorry for my ignoranceIncommensurable
Which ever you like ;) If in doubt I would start with Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()) for a CPU bound process. This will ensure you can use every core with a minimum of overhead.Argil
@PeterLawrey All's working fine now. Thanks. one more doubt. I am starting a thread for each of the queries, and calculating the total time taken/no of queries which gives the avg time. But there is not much diff in the avg time if I use 10 queries or 500 queries. Is that fine or is there an issue?Incommensurable
The only issue is that it is surprising that more queries don't take longer. It suggests that perhaps your queries are similar to each other and perhaps when one is done and cached, they are all done.Argil
Yup I am expecting it to take longer. And yea my queries are quite similar which might be causing the issue. Hopefully it'l be fine with a diff set of queries. Thanks a lot!Incommensurable
It would appear that the overhead of having the pool and multiple threads/tasks is small compared to the time each task takes.Argil
@PeterLawrey -- Regarding "It would appear that the overhead of having the pool and multiple threads/tasks is small compared to the time each task takes", how do you decide it? Suppose I have two service calls to make and both can be done parallelly where both the calls take an avg of 450ms each, does calling them via Future makes sense or sequentially is better?Agon
@CroskCool 450 ms is long time for a computer so breaking it up and passing it between threads is likely to help.Argil
O
3

Use a CountDownLatch like mentioned here.

public class StopLatchedThread extends Thread {
  private final CountDownLatch stopLatch;

  public StopLatchedThread(CountDownLatch stopLatch) {
    this.stopLatch = stopLatch;
  }
  public void run() {
    try {
      // perform interesting task
    } finally {
      stopLatch.countDown();
    }
  }
}

public void performParallelTask() throws InterruptedException {
  CountDownLatch cdl = new CountDownLatch(10);
  for (int i = 0; i < 10; i++) {
    Thread t = new StopLatchedThread(cdl);
    t.start();
  }
  cdl.await();
}
Oro answered 8/8, 2012 at 7:22 Comment(0)
N
1

You need another Thread to wait until these 1000 Threads have finished their work, you can do that with a CountDownLatch, but you need to know the exact number of Threads that you have - 1000 in your case.

Something like this:

public class LatchTest {
    public static void main(String[] args) throws Exception {

        final CountDownLatch latch = new CountDownLatch(100);

        long startTime = System.nanoTime();
        for(int i=0;i<100;++i){
            new Thread(new Runnable() {
                public void run() {
                    //Simulate some work
                    latch.countDown();
            }).start();
        }

        // Main Thread will wait for all Threads to finish
        latch.await();
        long finishTime = System.nanoTime();
        System.out.println("Have passed : " + (finishTime - startTime));
    }
}
Narva answered 8/8, 2012 at 7:21 Comment(0)
M
1

Why not throw them all into an Executor, and call get() on each resultant Future in turn?

Once the last thread completes, then you'll have called your last get() and you can time that complete operation.

Mongol answered 8/8, 2012 at 7:28 Comment(0)
W
1

In general you cannot measure time execution exactly because context switching. If you have 1000 threads it is produce significant impact to all time measuring. Nevertheless if you may omit high exactness of time measuring you may use CountDownLautching primitive to synchronizing thread starting and thread finishing:

    public static void main( String[] args ) throws InterruptedException {
    final int THREAD_COUNT = 10000;
    long startTime;
    long endTime;
    final CountDownLatch startBarierr = new CountDownLatch(THREAD_COUNT + 1);
    final CountDownLatch finishBarierr = new CountDownLatch(THREAD_COUNT);
    for (int i = 0; i < THREAD_COUNT; i++){
        final int iterationIndex = i;
        new Thread(new Runnable() {
            @Override
            public void run() {
                startBarierr.countDown();
                System.out.println("Thread " + iterationIndex + " started");
                try {
                    startBarierr.await();
                    //do some work in separate thread
                    int iterationCount = (int)(0.8*Integer.MAX_VALUE);
                    for(int i = 0; i < iterationCount; i++){

                    }
                    System.out.println("Thread " + iterationIndex + " finished");
                    finishBarierr.countDown(); //current thread finished, send mark
                } catch (InterruptedException e) {
                    throw new AssertionError("Unexpected thread interrupting");
                }
            }
        }).start();
    }
    startBarierr.countDown();
    startBarierr.await(); //await start for all thread
    startTime = System.currentTimeMillis(); //and note time
    finishBarierr.await(); //wait each thread
    endTime = System.currentTimeMillis();   //note finish time
    System.out.println("Time(ms) - " + (endTime - startTime));
}
Winthorpe answered 8/8, 2012 at 7:49 Comment(0)
S
0

Probably the easiest way is to put those Threads on a list and checking in intervals whether any of them is alive (Thread.isAlive() method), taking the dead ones off the list. Repeat until list is empty. Downside is that it'll give you the time with some error margin.

The other solution is to inject 'parent' controller into those threads, then make them report back upon finishing. The same logic applies - we can pull a finished thread from list (or some other kind of set) until our list is empty. This method is more precise, but requires adding additional logic into threads.

Sandalwood answered 8/8, 2012 at 7:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.