Выполнение некоторого кода только один раз в области потока
В определенной части 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();
}