我正在从我的代码中启动多个线程(大约 1000 个)。它们是从 while 循环调用的可运行线程。如何计算所有线程完成执行所需的总时间?
此外,我正在打开一个数据库连接并有一组查询,我正在为这些查询启动这些线程(1 个线程用于 1 个查询)。我什么时候关闭连接?
我正在从我的代码中启动多个线程(大约 1000 个)。它们是从 while 循环调用的可运行线程。如何计算所有线程完成执行所需的总时间?
此外,我正在打开一个数据库连接并有一组查询,我正在为这些查询启动这些线程(1 个线程用于 1 个查询)。我什么时候关闭连接?
我会使用 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);
完成后关闭连接。资源的创建者也关闭它是一种常见的模式。例如,如果主线程创建连接,它可以在所有线程完成后关闭。
使用此处提到的 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();
}
您需要另一个线程等待这 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));
}
}
通常,由于上下文切换,您无法准确测量时间执行。如果您有 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));
}
可能最简单的方法是将这些线程放在一个列表中,并每隔一段时间检查它们中的任何一个是否还活着(Thread.isAlive() 方法),将死线程从列表中删除。重复直到列表为空。缺点是它会给你一些误差范围的时间。
另一种解决方案是将“父”控制器注入这些线程,然后让它们在完成后报告。同样的逻辑也适用——我们可以从列表(或其他类型的集合)中拉出一个已完成的线程,直到我们的列表为空。这种方法更精确,但需要在线程中添加额外的逻辑。