5

我正在从我的代码中启动多个线程(大约 1000 个)。它们是从 while 循环调用的可运行线程。如何计算所有线程完成执行所需的总时间?

此外,我正在打开一个数据库连接并有一组查询,我正在为这些查询启动这些线程(1 个线程用于 1 个查询)。我什么时候关闭连接?

4

6 回答 6

8

我会使用 ExecutorService

long start = System.nanoTime();
ExecutorService service = Executors.newWhatEverPool();
for(loop)
   service.submit(new MyRunnable());

service.shutdown();
service.awaitTermination(1, TimeUnit.HOUR); // or longer.    
long time = System.nanoTime() - start;
System.out.printf("Tasks took %.3f ms to run%n", time/1e6);

完成后关闭连接。资源的创建者也关闭它是一种常见的模式。例如,如果主线程创建连接,它可以在所有线程完成后关闭。

于 2012-08-08T07:26:06.297 回答
3

使用此处提到的 CountDownLatch 。

public class StopLatchedThread extends Thread {
  private final CountDownLatch stopLatch;

  public StopLatchedThread(CountDownLatch stopLatch) {
    this.stopLatch = stopLatch;
  }
  public void run() {
    try {
      // perform interesting task
    } finally {
      stopLatch.countDown();
    }
  }
}

public void performParallelTask() throws InterruptedException {
  CountDownLatch cdl = new CountDownLatch(10);
  for (int i = 0; i < 10; i++) {
    Thread t = new StopLatchedThread(cdl);
    t.start();
  }
  cdl.await();
}
于 2012-08-08T07:22:17.063 回答
1

您需要另一个线程等待这 1000 个线程完成工作,您可以使用 CountDownLatch 来完成,但您需要知道您拥有的线程的确切数量 - 在您的情况下为 1000。

像这样的东西:

public class LatchTest {
    public static void main(String[] args) throws Exception {

        final CountDownLatch latch = new CountDownLatch(100);

        long startTime = System.nanoTime();
        for(int i=0;i<100;++i){
            new Thread(new Runnable() {
                public void run() {
                    //Simulate some work
                    latch.countDown();
            }).start();
        }

        // Main Thread will wait for all Threads to finish
        latch.await();
        long finishTime = System.nanoTime();
        System.out.println("Have passed : " + (finishTime - startTime));
    }
}
于 2012-08-08T07:21:31.640 回答
1

为什么不将它们全部放入Executor中,然后依次在每个结果Future上调用 get() ?

一旦最后一个线程完成,那么您将调用最后一个 get() 并且您可以为完成操作计时。

于 2012-08-08T07:28:36.963 回答
1

通常,由于上下文切换,您无法准确测量时间执行。如果您有 1000 个线程,则会对所有时间测量产生重大影响。不过,如果您可以省略高精度的时间测量,您可以使用 CountDownLautching 原语来同步线程启动和线程完成:

    public static void main( String[] args ) throws InterruptedException {
    final int THREAD_COUNT = 10000;
    long startTime;
    long endTime;
    final CountDownLatch startBarierr = new CountDownLatch(THREAD_COUNT + 1);
    final CountDownLatch finishBarierr = new CountDownLatch(THREAD_COUNT);
    for (int i = 0; i < THREAD_COUNT; i++){
        final int iterationIndex = i;
        new Thread(new Runnable() {
            @Override
            public void run() {
                startBarierr.countDown();
                System.out.println("Thread " + iterationIndex + " started");
                try {
                    startBarierr.await();
                    //do some work in separate thread
                    int iterationCount = (int)(0.8*Integer.MAX_VALUE);
                    for(int i = 0; i < iterationCount; i++){

                    }
                    System.out.println("Thread " + iterationIndex + " finished");
                    finishBarierr.countDown(); //current thread finished, send mark
                } catch (InterruptedException e) {
                    throw new AssertionError("Unexpected thread interrupting");
                }
            }
        }).start();
    }
    startBarierr.countDown();
    startBarierr.await(); //await start for all thread
    startTime = System.currentTimeMillis(); //and note time
    finishBarierr.await(); //wait each thread
    endTime = System.currentTimeMillis();   //note finish time
    System.out.println("Time(ms) - " + (endTime - startTime));
}
于 2012-08-08T07:49:16.193 回答
0

可能最简单的方法是将这些线程放在一个列表中,并每隔一段时间检查它们中的任何一个是否还活着(Thread.isAlive() 方法),将死线程从列表中删除。重复直到列表为空。缺点是它会给你一些误差范围的时间。

另一种解决方案是将“父”控制器注入这些线程,然后让它们在完成后报告。同样的逻辑也适用——我们可以从列表(或其他类型的集合)中拉出一个已完成的线程,直到我们的列表为空。这种方法更精确,但需要在线程中添加额外的逻辑。

于 2012-08-08T07:24:31.210 回答