等待池完成线程
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());
我正在尝试 运行 对上面的代码进行一些性能测试。我正在尝试在不同的 Runnable
上使用相同的 executor
并测量时间。但它并不完全有效。第一个 "total time" 不正确,以毫秒为单位。
我想在第一个循环中打印经过的时间,然后在第二个循环中打印。不确定如何等待执行程序完成第一个然后重新启动执行程序。
完成这项工作的正确方法是什么?
您现在正在做的是:
- 启动秒表
- 启动几个线程
- 阅读秒表
您不会像处理第二个循环那样等待它们完成。
这是您可以解决此问题的方法。
在 SingleConnectionRunnable 中创建一个回调方法。
此方法将在此可运行对象的最后一点(当您终止它时)调用,并被启动循环的 class 捕获(这不是问题中的方法,但没关系)。
在此回调方法中,您可以跟踪它被调用的次数。
当它调用 MYTHREAD 次数时,您打印秒表时间。
现在您知道完成所有启动的线程需要多长时间了。
首先,awaitTermination
会 block until all tasks terminate. Is there any particular reason that you use a while loop check after waiting potentially 70 years?
无论如何,要回答你的问题,为了等待第一个 运行 完成,你应该使用 CountDownLatch
来表示每个线程的完成并在主线程中等待它们直到他们完成了。您还可以使用 CyclicBarrier
等待,直到所有线程都准备就绪,然后再开始计时,如下所示:
...
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();
...
我将 sw.start()
移到了 for-loop 的开头,以避免测量对象分配的设置开销(可能无论如何都不会测量,因为它以毫秒为单位)。
也可以将两个并发类重置为运行无限次。
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());
我正在尝试 运行 对上面的代码进行一些性能测试。我正在尝试在不同的 Runnable
上使用相同的 executor
并测量时间。但它并不完全有效。第一个 "total time" 不正确,以毫秒为单位。
我想在第一个循环中打印经过的时间,然后在第二个循环中打印。不确定如何等待执行程序完成第一个然后重新启动执行程序。
完成这项工作的正确方法是什么?
您现在正在做的是:
- 启动秒表
- 启动几个线程
- 阅读秒表
您不会像处理第二个循环那样等待它们完成。
这是您可以解决此问题的方法。
在 SingleConnectionRunnable 中创建一个回调方法。
此方法将在此可运行对象的最后一点(当您终止它时)调用,并被启动循环的 class 捕获(这不是问题中的方法,但没关系)。
在此回调方法中,您可以跟踪它被调用的次数。
当它调用 MYTHREAD 次数时,您打印秒表时间。
现在您知道完成所有启动的线程需要多长时间了。
首先,awaitTermination
会 block until all tasks terminate. Is there any particular reason that you use a while loop check after waiting potentially 70 years?
无论如何,要回答你的问题,为了等待第一个 运行 完成,你应该使用 CountDownLatch
来表示每个线程的完成并在主线程中等待它们直到他们完成了。您还可以使用 CyclicBarrier
等待,直到所有线程都准备就绪,然后再开始计时,如下所示:
...
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();
...
我将 sw.start()
移到了 for-loop 的开头,以避免测量对象分配的设置开销(可能无论如何都不会测量,因为它以毫秒为单位)。
也可以将两个并发类重置为运行无限次。