2012-05-24 6 views
5

私がアプリケーションをプロファイリングしたとき、このメソッドによって作成されたスケジュールされたスレッドは実行前に常に「実行中」状態ではなく「実行中」であることに気づきました。 executorService.shutdown()を削除すると、必要な処理が実行されます(スレッドは実行するまで待機状態になります)。ただし、executorService.shutdown()がなければ、実行後にnonDaemonスレッドはガベージコレクションされません。実行前にスレッドが常に待機状態にあることを保証する方法はありますか?または他のどのような代替私はそれを確実にするために、この方法のために使用することができます。シャットダウンされたScheduledExecutorServiceでスレッドの待機を維持する方法

  • 私はエグゼキュータのサービスで実行されるスレッドの名前に接頭辞を付けることができます(つまり、DefaultThreadFactory実装が何をするか効果的です)
  • 非デーモン実行後にスレッドはGCを取得します。
  • 作成されたスレッドは、実行するまで待機状態のままです。

答えて

2

解答:保留中のすべてのタスクスレッドの状態を 'waiting'から 'running'に変更するshutdown()です。すぐにshutdown()を呼び出すのではなく、executorServiceを使用して独自のshutdown()への呼び出しをスケジュールします。これにより、保留中のタスクはできるだけ待ち状態に留まり、CPUリソースが節約されます。

public ScheduledFuture<?> executeTaskWithDelay(String name, 
     final Runnable runnable, Period delay, boolean isDaemon) { 
    final ScheduledExecutorService executorService = 
     Executors.newSingleThreadScheduledExecutor(new DefaultThreadFactory(
     name, isDaemon)); 
    ScheduledFuture<?> future = executorService.schedule(runnable, 
     delay.toStandardDuration().getMillis(), TimeUnit.MILLISECONDS); 

    executorService.schedule(new Runnable() { 
     @Override 
     public void run() { 
     executorService.shutdown(); 
     }}, delay.toStandardDuration().getMillis(), TimeUnit.MILLISECONDS); 

    return future; 
} 
+0

+1よくできました。私はこれを解決策として提案することを考えていましたが、1つのタスクが(実行カウントのような他のタイプのコントロールなしで)スケジュールに提出された場合にのみ機能するので、私はオプトアウトしました。 –

0

あなたのコードを実行してください。問題という結論に私をリード

944   // It is possible (but unlikely) for a thread to have been 
945   // added to workers, but not yet started, during transition to 
946   // STOP, which could result in a rare missed interrupt, 
947   // because Thread.interrupt is not guaranteed to have any effect 
948   // on a non-yet-started Thread (see Thread#interrupt). 
949   if (runStateOf(ctl.get()) == STOP && ! t.isInterrupted()) 
950    t.interrupt(); 

:これはそのThreadPoolExecutor.java:950ためgrepcodeからで、今

"bla" prio=5 tid=7fa2bc16a000 nid=0x10bd53000 runnable [10bd52000] 
    java.lang.Thread.State: RUNNABLE 
    at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:950) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907) 
    at java.lang.Thread.run(Thread.java:680) 

    Locked ownable synchronizers: 
    - None 

:これは(私がスレッド「BLA」という名前)jvisualvmでスレッドダンプからですあなたのテストコードにあります - あなたは実行者をあまりにも速くシャットダウンしていて、スレッドは奇妙な状態で自分自身を見つけます。これは実動コードでは問題ではありません。

+0

タスクがスケジュールされるのを待っている間に実行者をシャットダウンすると、これが生産上の問題になります。 –

+0

@JohnVintこの特定のコード行は、まれに、 'start'メソッドが実行された直後にスレッドが' STOP'状態に入るまれに(コメントとして説明しているように)実行されます(943行目です) 。おそらく、この特定の問題ではなく、一般的な問題を意味します。 –

+0

Topolink ExecutorServiceが 'shutdownNow()' Executorの状態で 'shutdown()'が 'SHUTDOWN'のときにのみ' STOP'状態がセットされます。 –

2

あなたが見ているのは、シャットダウン機能のためにプレーンなThreadPoolExecutorに委任されたScheduledExecutorです。 TPEをシャットダウンすると、すべてのスレッドが空になるまでバッキング作業キューで回転します。まあ、ScheduledThreadPoolは空ではないかもしれないDelayedQueueを使用しますが、もしあなたがpoll'dすれば、タスクがスケジュールする準備ができていないので、あなたはnullを返すでしょう。それは準備が整うまで回転して回転します

あなたが本当に行うことができるのは、shutdownNowで、他の方法で返すタスクを実行することだけです。

はまた、私は、これは実際にあなたがdidn't future.get()メソッドを呼び出すためのスレッドが待機していないされているJava 7

+0

+1最初の2つの文が解決策を助けました。 – Kes115

3

に固定されていると言われています。 私はそれを証明するために単体テストを行いました。

テスト(future.get()メソッドを呼び出すことなく)#1:

@Test 
public void testSchedule() throws InterruptedException, ExecutionException { 

    ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); 
    System.out.println(new Date()); 
    ScheduledFuture<?> future = executorService.schedule(new Runnable() { 

     public void run() { 
      System.out.println(Thread.currentThread().getId() + " - " + Thread.currentThread().getName() + " - Executing thread...");     
     } 

    }, 5, TimeUnit.SECONDS); 

    //System.out.println("future : " + future.get()); 

    executorService.shutdown(); 
    System.out.println(new Date()); 
} 

、出力があった:

Thu May 24 10:11:14 BRT 2012 
Thu May 24 10:11:14 BRT 2012 

テスト#2(呼び出しfuture.get()メソッド)。

@Test 
public void testSchedule() throws InterruptedException, ExecutionException { 

    ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); 
    System.out.println(new Date()); 
    ScheduledFuture<?> future = executorService.schedule(new Runnable() { 

     public void run() { 
      System.out.println(Thread.currentThread().getId() + " - " + Thread.currentThread().getName() + " - Executing thread...");     
     } 

    }, 5, TimeUnit.SECONDS); 

    System.out.println("future : " + future.get()); 

    executorService.shutdown(); 
    System.out.println(new Date()); 
} 

そして、出力されました:

Thu May 24 10:12:48 BRT 2012 
8 - pool-1-thread-1 - Executing thread... 
future : null 
Thu May 24 10:12:53 BRT 2012 

私はそれがあなたを助けてくれることを願っています!

+0

私はOPを見落としていない限り、彼は提出スレッド(タスクの完了を待っているスレッド)を参照しているとは思わない。私は彼が継続的に実行されているExecutorServiceのスレッドを参照していると思います。違いを観察するには、Marko Topolnikのスレッドダンプを参照してください。 –

+0

@JohnVintが正しいです。 – Kes115

関連する問題