1

次のような構造の Java アプリケーションがあります。

  • 1 つのスレッドjava.nio.Selectorが IO を監視しています。
  • java.util.concurrent.ScheduledThreadPoolExecutorすぐに実行される作業 (IO スレッドによって読み取られた IO をディスパッチする) または遅延後に実行される作業 (通常はエラー) のいずれかを処理するスレッド プール。

ScheduledThreadPoolExecutorは、作成するスレッド数の上限があります。現在アプリで 5000 ですが、私はその数をまったく調整していません。

アプリをしばらく実行した後、次のスタック トレースを持つ何千ものスレッドを取得します。

"pool-1-thread-5262" prio=10 tid=0x00007f636c2df800 nid=0x2516 waiting on condition [0x00007f60246a5000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x0000000581c49520> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:196)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2025)
        at java.util.concurrent.DelayQueue.poll(DelayQueue.java:209)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.poll(ScheduledThreadPoolExecutor.java:611)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.poll(ScheduledThreadPoolExecutor.java:602)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:945)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
        at java.lang.Thread.run(Thread.java:662)

上記は への呼び出しによって引き起こされていると思いますがschedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit)、これは確かにアプリで頻繁に発生します。これは予想される動作ですか?

これらすべてのスレッドがぶらぶらしていても、アプリケーションにはまったく影響がないようです— ワーカー スレッドが必要な場合、メソッドTIMED_WAITINGを介して送信されたときにこれらのスレッドがタスクの実行を妨げているようには見えませんがsubmit、完全には確信が持てません。それ。この保留状態で何千ものスレッドがぶらぶらしていると、アプリやシステムのパフォーマンスに影響がありますか?

メソッドを介して送信されるタスクscheduleは非常に単純です。基本的にChannelは、Selector. したがって、これらのタスクはそれほど長く存続するわけではなく、将来のある時点で実行する必要があるだけです。通常のワーカー スレッドは、従来のブロッキング IO を実行して作業を実行し、一般に寿命が長くなります。

関連する質問: メソッドを使用する代わりに、明示的なシングル スレッドで遅延タスクを実行する方がよいscheduleでしょうか? つまり、次のようなループがあります。

DelayedQueue<SomeTaskClass> tasks = ...;
while (true) {
    task<SomeTaskClass> = tasks.take();
    threadpool.submit(task);
}

DelayQueue はワーカー スレッドを使用してその機能を実装しますか? 今日はただ実験するつもりでしたが、アドバイスをいただければ幸いです。

4

1 に答える 1

1

アプリをしばらく実行した後、このスタック トレースを含む何千ものスレッドを取得します。

一度に 5000 のスレッドをすべて動作させることを実際に計画していない限り、これは多すぎます。IO でブロックされている場合は問題ありません。大きすぎる最小数のスレッドで開始しない限り、スレッド ダンプにスレッドが存在するということは、ある時点でエグゼキュータに送信されたタスクを処理するためにすべてのスレッドが必要になったことを意味します。そのため、ある時点で一度に 5000 のタスクが実行されていました (ブロックなど)。実際のエグゼキューター コンストラクター呼び出しを表示すると、より具体的にすることができます。

時間があれば、その上限を試してみて、アプリケーションの動作に影響があるかどうかを確認してください。

この保留状態で何千ものスレッドがぶらぶらしていると、アプリやシステムのパフォーマンスに影響がありますか?

JVM のパフォーマンスに影響を与える可能性のあるより多くのメモリを消費しますが、一度に多数のアプリケーションを実行しない限り、アプリケーションに影響を与えることはありません。システム リソースを浪費しているだけかもしれません。これが、5000 およびその他のエグゼキュータ コンストラクタの引数をいじる唯一の理由です。

スケジュール メソッドを使用する代わりに、明示的なシングル スレッドで遅延タスクを実行する方がよいでしょうか?

いいえと思います。ほぼいつでも、手動のスレッド コードをExecutorServiceクラスの使用に置き換えることができるのは良いことです。タスクを実行してからしばらく遅らせるというアイデアは、 の優れた使い方だと思いますScheduledThreadPoolExecutor

DelayQueue はワーカー スレッドを使用してその機能を実装しますか?

BlockingQueueいいえ。これは、タスクの遅延に役立つ単なる実装です。私はクラスを実際に使用したことはありませんが、知っていれば使用していたでしょう。はこのScheduledThreadPoolExecutorクラスを使用してジョブを実行するため、DelayQueue自分自身を使用するのも無駄です。STPEに固執するだけです。

于 2012-07-03T18:33:40.653 に答える