2012-04-13 13 views
0

スレッドの寿命を監視する方法があるかどうかを知りたいですが、私がやっていることのコンテキストを説明して、これを行う良い方法があるかもしれません。スレッドの寿命を監視するにはどうすればよいですか?

基本的に私は、スレッドが受け入れ可能な結果を​​得た場合、キュー上で処理しているx個のスレッドを持っています。そうでなければ、データは破棄されるか、さらに処理されます。

私の問題は私のメインスレッドにあります。while(!solutions_results.isEmpty())のようなものがあり、データを保存します。明らかな問題は、ソリューションがキューをクリアしてから完了し、他のスレッドが依然としてキューにデータを入れているにもかかわらず作業が完了した後です。

私はこの問題に対処するための最良の方法はないでしょうか(多分、ソリューションキューを保存するだけの専用スレッドがありますか?)私は何とか他のスレッドの寿命を監視できればいいと思っていました。より多くのデータがソリューションキューに入る可能性があります。

これを行うより良い方法がある場合は、私に他のスレッドが完了したことを伝える方法があることを私に教えてください。(このプロセスを実行する前にエグゼキュータが完了するのを待つことはできません。メモリに座って、理想的にはそれが近づくにつれてそれを処理したいが時間依存ではないことを望んでいないのですか?

+0

これは[生産者の消費者問題](http://en.wikipedia.org/wiki/Producer-consumer_problem)です。たぶんその記事はあなたにいくつかの洞察を与えるでしょう。 – jpm

+0

@jpmそんなにありがとう、私はそれを読むでしょう.. –

答えて

2

あなたがスレッドのジョブを実行するためにExecutorServiceを使用している場合、あなたはすべてのスレッドが終了した時に知ってawaitTermination()メソッドを使用することができます。

ExecutorService pool = Executors.newFixedThreadPool(10); 
pool.submit(yourSolutionsRunnable); 
pool.submit(yourSolutionsRunnable); 
... 
// once you've submitted your last job you can do 
pool.shutdown(); 

次にあなたがフィニッシュに送信されたジョブのすべてのを待つことができます:

pool.waitTermination(Integer.MAX_VALUE, TimeUnit.MILLISECONDS); 

解決策を提出した後にスレッドを実行し続ける必要がある場合、これはさらに複雑になります。あなたがあなたの質問を編集し、これをより明白にすると私は自分の答えを編集します。


編集:

ああ、私はあなたが道に沿っていくつかの結果を処理するが、すべてのスレッドが完了するまで停止しないようにしたい参照してください。

すべてのジョブが完了したかどうかを示すpool.isTerminated()テストを使用できます。だからあなたのループは次のようになります。

// this is the main thread so waiting for solutions in a while(true) loop is ok 
while (true) { 
    // are all the workers done? 
    if (pool.isTerminated()) { 
     // if there are results process one last time 
     if (!solutions_results.isEmpty()) { 
      processTheSolutions(); 
     } 
     break; 
    } else { 
     if (solutions_results.isEmpty()) { 
      // wait a bit to not spin, you could also use a wait/notify here 
      Thread.sleep(1000); 
     } else { 
      processTheSolutions(); 
     } 
    } 
} 

編集:

あなたはまた、2つのスレッド・プール、ソリューション、別の処理を生成するための1つを持つことができます。メインスレッドは、ワーカープールが空になるのを待ってから、ソリューション処理プールを待ちます。ワーカープールは、ソリューションプール(存在する場合)をソリューションプールに提出する。必要に応じて、ソリューション処理プールに1つのスレッドしか持たないかもしれません。

ExecutorService workerPool = Executors.newFixedThreadPool(10); 
final ExecutorService solutionsPool = Executors.newFixedThreadPool(1); 
solutionsPool.submit(workerThatPutsSolutionsIntoSolutionsPool); 
... 
// once you've submitted your last worker you can do 
workerPool.shutdown(); 

workerPool.waitTermination(Integer.MAX_VALUE, TimeUnit.MILLISECONDS); 
// once the workers have finished you shutdown the solutions pool 
solutionsPool.shutdown(); 
// and then wait for it to finish 
solutionsPool.waitTermination(Integer.MAX_VALUE, TimeUnit.MILLISECONDS); 
+0

しかし、それはすべてのスレッドが完了するまで解決待ち行列の私の処理を待つことを妨げるでしょうか?スレッドが生きている間にソリューションのキューを実行し続ける方法があるので、whileループでラップすることはできますか? –

+0

あなたの右がグレーで、スレッドはまだ実行中です。 1つは作業キューで、もう1つは解決キューです。作業キューが空でない限り、私はそれを処理する固定数のスレッドを持っています。 –

+0

ありがとうグレイ。出来た!私は、データセットが小さく、このプロセスがスリープしている間にスレッドが終了すると、2つ目の編集で 'if(pool.isTerminated()){'が終了するだけで1つの部分を修正する必要がありました。私は 'if(executor.isTerminated()&& solutions_results.isEmpty()){'に変更して動作するようです。私はもっ​​とテストしますが、これはまさに私が探していたものです。良い週末を。 –

0

私が扱っている動作要件についてはよく分かりませんが、すべての子スレッドが完了するまでメインスレッドをブロックしたい場合は、Threadクラスのjoinメソッドを見てください。

http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()

ただ、それぞれ自分の子スレッドの1とするとき、それはあなたがすべてのスレッドが作業を終了したことを確認することができますループを抜けるには、joinメソッドを呼び出して、あなたのメインスレッド内でループを実行します。

+0

しかし、それは私のプログラムが開始する前にすべてのプロセスが完了するのを待つか?プログラムは非常に長い時間実行され、私はむしろそれが来るようにそれに対処したい。 –

+0

ああ、私は質問を誤解した。 –

+0

問題はない、私はこの権利を説明していない時間の99%を学んでいるので、新しいです。 –

0

アクティブなスレッドのリストを保持するだけです。同時にスレッドを追加/削除すると、そのスレッドがゴミ箱にならないように同期させることができます。または、java.util.concurrent.ConcurrentLinkedQueueのようなものを使用してください。これは、複数のスレッド自体を処理できます。開始時に各スレッドをリストに追加します。各スレッドは、停止する直前にリストから削除する必要があります。リストが空の場合、すべてのスレッドが完了します。

編集:タイミングが重要です。 まず、メインスレッドは作業スレッドをリストに入れなければなりません。彼らがリストに載っていれば、メインスレッドは、リストから自分自身を削除し、残りのすべてのスレッドがまだ実行を開始していないときにリストをチェックすることができます。リスト。それはそうでないときにすべてが完了したと思うでしょう。 第2に、メインスレッドは、の各ワーカースレッドをの前に置く必要があります。それ以外の場合、スレッドは終了し、リストから自身を削除しようとします。の前にスレッドがそれをリストに追加します。リストは空にならず、プログラムは決して終わらないでしょう。

0

多分java.util.concurrent.ExecutorCompletionServiceはここで便利です。

import java.util.ArrayList; 
import java.util.Collection; 
import java.util.List; 
import java.util.concurrent.Callable; 
import java.util.concurrent.CancellationException; 
import java.util.concurrent.CompletionService; 
import java.util.concurrent.ExecutionException; 
import java.util.concurrent.ExecutorCompletionService; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

public class monitor_life_of_threads 
{ 
    /** 
    * First, convert all of your threads to instances of Callable (easy to do), and have them each return an instance some class (I'm using Integer below just as 
    * an example). 
    * This will help simplify things. 
    */ 

    public static void main (String args[]) 
    { 
     final monitor_life_of_threads worker = new monitor_life_of_threads(); 

     worker.executeCallablesAndUseResults(); 

     System.exit (0); 
    } 

    private void executeCallablesAndUseResults() 
    { 
     List < Callable <Result>> list = new ArrayList <>(); 
     populateInputList (list); 

     try 
     { 
      doWork (list); 
     } 
     catch (InterruptedException e) 
     { 
      e.printStackTrace(); 
     } 
     catch (ExecutionException e) 
     { 
      e.printStackTrace(); 
     } 
     catch (CancellationException e) 
     { 
      /* 
      * Could be called if a Callable throws an InterruptedException, and if it's not caught, it can cause Future.get to hang. 
      */ 
      e.printStackTrace(); 
     } 
     catch (Exception defaultException) 
     { 
      defaultException.printStackTrace(); 
     } 
    } 

    private void doWork (Collection < Callable <Result>> callables) throws InterruptedException, ExecutionException 
    { 
     ExecutorService executorService = Executors.newCachedThreadPool(); 

     CompletionService <Result> ecs = new ExecutorCompletionService < > (executorService); 

     for (Callable <Result> callable : callables) 
      ecs.submit (callable); 

     for (int i = 0, n = callables.size(); i < n; ++i) 
     { 
      Result r = ecs.take().get(); 
      if (r != null) 
       use (r); // This way you don't need a second queue. 
     } 

     executorService.shutdown(); 

    } 

    private void use (Result result) 
    { 
     // Write result to database, output file, etc. 

     System.out.println ("result = " + result); 
    } 

    private List < Callable <Result>> populateInputList (List < Callable <Result>> list) 
    { 
     list.add (new Callable <Result>() { 

      @Override 
      public Result call() throws Exception 
      { 
       // Do some number crunching, then return a 5. 
       return new Result (5); 
      } 

     }); 

     list.add (new Callable <Result>() { 

      @Override 
      public Result call() throws Exception 
      { 
       // Do some number crunching, then return an 8. 
       return new Result (8); 
      } 

     }); 

     list.add (new Callable <Result>() { 

      @Override 
      public Result call() throws Exception 
      { 
       // Do some number crunching, but fail and so return null. 
       return null; 
      } 

     }); 

     return list; 
    } 
} 

class Result 
{ 
    private Integer i; 

    Result (Integer i) 
    { 
     this.i = i; 
    } 

    public String toString() 
    { 
     return Integer.toString (i); 
    } 
} 
関連する問題