Executing some code only once in a Thread region

212 Views Asked by At

In a certain part of a Java code that i am working, i need to place a timer inside a run() method. Each thread will execute all code inside run(). But i need to start measuring after block (1) and before block of code (2) so the timer needs to be triggered there.

for (int i = 0; i < total_threads-1; i++){
   final int id = i+1;          
   th[i] = new Thread(new Runnable() {              
       public final void run(){
             /* ... block of code (1) executed by multiple threads ... */

             /* How can i start this counter only once? */
             final long begin = System.currentTimeMillis();

             /* ... another block of code (2) executed by multiple threads i need to measure!!! ... */
       }
    });
    th[i].start();
}

for(int i = 0 ; i < total_threads-1 ; i++) {
    try {
           th[i].join();
        }
    catch (InterruptedException e) {}
}

final long end = System.currentTimeMillis();

System.out.println((end-begin) / 1000.0);

But all the threads will have their own begin variable and start the counter which is a problem because System.currentTimeMillis() should be triggered once and not by many threads. I probably could separate the code of run() in two different parallel regions but would imply creating the threads twice which would be unacceptable (in terms of performance). There is a similar technique of OpenMP directive #pragma omp master for Java using Java threads? How can i measure the time correctly here?

2

There are 2 best solutions below

1
On

You can check the thread ID to execute prefer line once:

if (id == YOUR_THREAD_ID) 
{
     begin = System.currentTimeMillis();
}
4
On

The simplest way would just be to record the time in the master thread (i.e. the thread which creates all the children) instead of in the children themselves.

But if you really want to start the timer in the children (maybe there's some expensive setup?), you could use a Guava StopWatch object.

The code would look something like:

StopWatch timer = StopWatch.createUnstarted();
for (int i = 0; i < total_threads-1; i++){
    final int id = i+1;
    th[i] = new Thread(() -> {
        /* ... block of code (1) executed by multiple threads ... */

        try {
            synchronized (timer) {
                timer.start();
            }
        } catch (IllegalStateException e) {
            // ignore; the watch is already started
        }

        /* ... another block of code (2) executed by multiple threads i need to measure!!! ... */
    });
    th[i].start();
}

for(int i = 0 ; i < total_threads-1 ; i++) {
    try {
        th[i].join();
    } catch (InterruptedException e) {}
}

timer.stop();

System.out.println(timer.elapsed(TimeUnit.SECONDS));