等待池完成线程

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" 不正确,以毫秒为单位。

我想在第一个循环中打印经过的时间,然后在第二个循环中打印。不确定如何等待执行程序完成第一个然后重新启动执行程序。

完成这项工作的正确方法是什么?

您现在正在做的是:

  1. 启动秒表
  2. 启动几个线程
  3. 阅读秒表

您不会像处理第二个循环那样等待它们完成。


这是您可以解决此问题的方法。

在 SingleConnectionRunnable 中创建一个回调方法。

此方法将在此可运行对象的最后一点(当您终止它时)调用,并被启动循环的 class 捕获(这不是问题中的方法,但没关系)。

在此回调方法中,您可以跟踪它被调用的次数。

当它调用 MYTHREAD 次数时,您打印秒表时间。

现在您知道完成所有启动的线程需要多长时间了。

首先,awaitTerminationblock 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 的开头,以避免测量对象分配的设置开销(可能无论如何都不会测量,因为它以毫秒为单位)。

也可以将两个并发类重置为运行无限次。