基本的に、このような行動は、スプリングによって内部的に使用されScheduledExecutorService
実装から来ています。あなたはこのコードを実行する場合は、同じ動作をわかります。
public static void main(String[] args) throws Exception {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
executor.schedule(() -> {
System.out.println("Running task in thread " + Thread.currentThread().getId());
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
System.out.println("interrupted while sleeping");
}
}, 1000, TimeUnit.MILLISECONDS);
Thread.sleep(10000);
executor.shutdownNow();
}
スケジュールスレッドプールにタスクを送信すると、それがdelayedExecute
メソッドに渡されRunnableScheduledFuture
に包まれています。このメソッドは、タスクをキューに追加し、現在のワーカー数がcorePoolSize
未満の場合は新しいワーカーを開始します。ワーカーは、キューからタスクを取得し、それを処理してrun
メソッドを呼び出そうとします。実行の準備ができている場合にのみタスクを返す専用のDelayedWorkQueue
実装があります。 reExecutePeriodic
はほぼ同じである(あなたはそれがrunAndReset
で実際のタスク・ロジックを呼び出す見ることができるように、
/**
* Overrides FutureTask version so as to reset/requeue if periodic.
*/
public void run() {
boolean periodic = isPeriodic();
if (!canRunInCurrentRunState(periodic))
cancel(false);
else if (!periodic)
ScheduledFutureTask.super.run();
else if (ScheduledFutureTask.super.runAndReset()) {
setNextRunTime();
reExecutePeriodic(outerTask);
}
}
次の実行時間を計算し、再びキューに同じ更新タスクを送信します。ここRunnableScheduledFuture
のrun
方法がどのように見えるかですschedule
)。直前の実行が終了してから更新された時間に何度も再実行されるすべての実行に対して1つの定期的なタスクしかありません。したがって、そのようなスレッドプールは、任意の瞬間に各タスクタイプの単一のインスタンスのみを実行し、異なるタイプのタスクに対してのみスケーリングします。
春スケジュールのタスクが興味深い場合は、ScheduledTaskRegistrar
クラス、特にscheduleFixedDelayTask
メソッドを参照してください。
私が観察したことは、Thread.sleepを使用するか、pool-size 10の@scheduledメソッド内でロックすると、スレッドが1回だけ実行されて永久にロックされるということです。たとえば、1つのスレッドが10のプールからスケジュールされた方法で実行され、1つのスレッドがロックにスタックされた場合、他の9つのスレッドはスケジュールされたメソッドメソッドに対して実行されません。すべてが固まった。たとえ私が睡眠を使ったとしても。 –
あなたのコードと要点を共有できますか?というのは、コードがシングルスレッドを使用しているように見えるからです。 – Makoton
スケジュールアノテーションで@Asyncのみを追加する必要があります。 –