0

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

基本的に、キューで作業して処理している x スレッドがあります。スレッドが許容可能な結果を​​取得した場合、それはソリューション キューに入ります。それ以外の場合、データは破棄されるか、さらに処理されます。

私の問題は、私が好きなメインスレッドにありwhile(!solutions_results.isEmpty())、データを保存します(現在はファイルに出力されますが、後でデータベースになる可能性があります)。明らかな問題は、他のスレッドがまだデータをキューに入れているにもかかわらず、ソリューション キューをクリアして作業を終了することです。

これに対処する最善の方法はわかりませんが (ソリューション キューのみを保存する専用スレッドを使用している可能性がありますか?)、何らかの方法で他のスレッドの寿命を監視できれば、データが増える可能性はないと考えていました。ソリューション キューに入ります。

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

4

4 に答える 4

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つは処理用です。次に、メインスレッドは、ワーカープールが空になるのを待ってから、ソリューション処理プールを待つことができます。ワーカープールは、ソリューション(存在する場合)をソリューションプールに送信します。必要に応じて、ソリューション処理プールに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);
于 2012-04-13T17:08:13.450 に答える
0

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

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

于 2012-04-13T21:02:38.267 に答える
0

扱っている動作要件についてはよくわかりませんが、すべての子スレッドが完了するまでメインスレッドをブロックする場合は、クラスのjoinメソッドを確認する必要があります。Thread

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

メインスレッド内で、子スレッドのそれぞれでjoinメソッドを呼び出すループを実行するだけで、ループを終了するときに、すべてのスレッドが機能していることを確認できます。

于 2012-04-13T17:07:17.493 に答える
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 );
    }
}
于 2013-09-30T00:41:46.803 に答える