コードから複数のスレッド (約 1000) を開始しています。while ループから呼び出される Runnable スレッドです。すべてのスレッドの実行が完了するまでの合計時間を計算するにはどうすればよいですか?
また、DB接続を開いていますが、これらのスレッドを開始する一連のクエリがあります(1クエリに対して1スレッド)。いつ接続を閉じるのですか?
コードから複数のスレッド (約 1000) を開始しています。while ループから呼び出される Runnable スレッドです。すべてのスレッドの実行が完了するまでの合計時間を計算するにはどうすればよいですか?
また、DB接続を開いていますが、これらのスレッドを開始する一連のクエリがあります(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));
}
}
それらをすべてExecutorに投入し、結果の Futureごとに順番に get() を呼び出してみませんか?
最後のスレッドが完了すると、最後の get() が呼び出され、その完了操作の時間を計ることができます。
一般に、コンテキストの切り替えが原因で実行時間を正確に測定することはできません。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() メソッド)、死んでいるスレッドをリストから削除することです。リストが空になるまで繰り返します。欠点は、多少の誤差を許容して時間を与えることです。
もう1つの解決策は、「親」コントローラーをそれらのスレッドに挿入し、終了時に報告するようにすることです。同じロジックが適用されます。リストが空になるまで、完成したスレッドをリスト (またはその他の種類のセット) から引き出すことができます。この方法はより正確ですが、スレッドに追加のロジックを追加する必要があります。