Выполнение некоторого кода только один раз в области потока

В определенной части Java-кода, с которым я работаю, мне нужно поместить таймер внутри run() метод. Каждый поток выполнит весь код внутри run(), Но мне нужно начать измерения после блока (1) и до блока кода (2), поэтому таймер должен быть запущен там.

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);

Но все темы будут свои begin переменная и запустить счетчик, который является проблемой, потому что System.currentTimeMillis() должен запускаться один раз, а не многими потоками. Я, вероятно, мог бы отделить код run() в двух разных параллельных областях, но это подразумевало бы создание потоков дважды, что было бы неприемлемо (с точки зрения производительности). Существует похожая методика директивы OpenMP #pragma omp master для Java с использованием потоков Java? Как я могу измерить время здесь правильно?

2 ответа

Простейшим способом было бы просто записать время в главном потоке (то есть в потоке, который создает все дочерние элементы), а не в самих дочерних элементах.

Но если вы действительно хотите запустить таймер у детей (может быть, есть дорогая настройка?), Вы можете использовать объект Guava StopWatch.

Код будет выглядеть примерно так:

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));

Вы можете проверить идентификатор потока, чтобы выполнить предпочтительную строку один раз:

if (id == YOUR_THREAD_ID) 
{
     begin = System.currentTimeMillis();
}
Другие вопросы по тегам