実行中のタスクごとに個別のスレッドが必要なので、アーキテクチャを変更することはできません。
それが当てはまる場合(たとえば、外部ブロッキング関数を呼び出す場合)、それらに対して個別のスレッドを作成し、それらを開始します。スレッドの 1 つのブロッキング機能により、他の実行可能ファイルがそこに入れられなくなり、タスクごとに 1 つのスレッドでスレッド プールを作成してもあまり効果がないため、限られた数のスレッドでスレッド プールを作成することはできません。
threadPool のサイズを Runtime.getRuntime().availableProcessors() に等しくしようとしましたが、これは 500 個のスレッドすべてを実行しようとしましたが、そのうちの 8 個 (4xhyperthreading) しか実行できませんでした。
作成している Thread オブジェクトをスレッド プールに渡すと、実装されていることがわかりますRunnable
。したがって、それぞれRunnable
が完了するまで実行されます。run()
メソッドの戻りを停止するループは、キューに入れられた次のタスクの実行を許可しません。例えば:
public static void main (String...args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
for (int i = 0; i < 10; ++i) {
final int task = i;
executor.execute(new Runnable () {
private long lastRunTime = 0;
@Override
public void run () {
for (int iteration = 0; iteration < 4; )
{
if (System.currentTimeMillis() - this.lastRunTime > TIME_OUT)
{
// do your work here
++iteration;
System.out.printf("Task {%d} iteration {%d} thread {%s}.\n", task, iteration, Thread.currentThread());
this.lastRunTime = System.currentTimeMillis();
}
else
{
Thread.yield(); // otherwise, let other threads run
}
}
}
});
}
executor.shutdown();
}
プリントアウト:
Task {0} iteration {1} thread {Thread[pool-1-thread-1,5,main]}.
Task {1} iteration {1} thread {Thread[pool-1-thread-2,5,main]}.
Task {0} iteration {2} thread {Thread[pool-1-thread-1,5,main]}.
Task {1} iteration {2} thread {Thread[pool-1-thread-2,5,main]}.
Task {0} iteration {3} thread {Thread[pool-1-thread-1,5,main]}.
Task {1} iteration {3} thread {Thread[pool-1-thread-2,5,main]}.
Task {0} iteration {4} thread {Thread[pool-1-thread-1,5,main]}.
Task {2} iteration {1} thread {Thread[pool-1-thread-1,5,main]}.
Task {1} iteration {4} thread {Thread[pool-1-thread-2,5,main]}.
Task {3} iteration {1} thread {Thread[pool-1-thread-2,5,main]}.
Task {2} iteration {2} thread {Thread[pool-1-thread-1,5,main]}.
Task {3} iteration {2} thread {Thread[pool-1-thread-2,5,main]}.
Task {2} iteration {3} thread {Thread[pool-1-thread-1,5,main]}.
Task {3} iteration {3} thread {Thread[pool-1-thread-2,5,main]}.
Task {2} iteration {4} thread {Thread[pool-1-thread-1,5,main]}.
...
次のタスクがスケジュールされる前に、最初の (スレッド プール サイズ) タスクが完了するまで実行されることを示しています。
あなたがする必要があるのは、しばらく実行するタスクを作成してから、他のタスクを実行させることです。これらをどのように構築するかは、何を達成したいかによって異なります
- すべてのタスクを同時に実行するか、すべてのタスクを 1 分間待ってからすべて同時に実行するか、またはタスクを互いに同期させないかどうか
- 各タスクを 1 分間隔で実行することが本当に必要かどうか
- タスクが潜在的にブロックされているかどうか、したがって実際には別のスレッドが必要かどうか
- 予想される実行ウィンドウよりも長くタスクがブロックされた場合に予想される動作
- タスクが繰り返し率よりも長くブロックされた場合 (1 分以上ブロックされた場合)、どのような動作が予想されるか
これらに対する回答に応じて、ScheduledExecutorService、セマフォ、またはミューテックスの組み合わせを使用して、タスクを調整できます。最も単純なケースは、ノンブロッキングで非同期のタスクです。この場合、ScheduledExecutorService を直接使用して、ランナブルを毎分 1 回実行します。