4

この問題のクリーンな設計/解決策を探しています。2つのスレッドがあり、ユーザーが望む限り実行できますが、ユーザーが停止コマンドを発行すると最終的に停止します。ただし、スレッドの1つが突然終了した場合(実行時の例外など)、もう1つのスレッドを停止したいと思います。

これで、両方のスレッドが実行されますRunnable(つまり、「スレッドを停止する」と言うときは、Runnableインスタンスでstop()メソッドを呼び出すということです)。私が考えているのは、スレッド(Threadクラス)の使用を避け、CompletionServiceインターフェイスを使用することです。次に、両方のRunnableをこのサービスのインスタンスに送信します。

これで、CompletionServiceのメソッドを使用しtake()ます。このメソッドが返されると、少なくとも1つがすでに終了していることがわかっているので、両方のRunnableを停止します。これでうまくいきますが、可能であれば、私の場合のより簡単でより良い解決策を知りたいと思います。

nまた、スレッドがあり、そのうちの1つが終了して他のすべての実行を停止するとすぐに、良い解決策は何ですか?

前もって感謝します。

4

3 に答える 3

7

メソッドがないRunnable.stop()ので、それは明らかに非スターターです。

使用しないでくださいThread.stop()ほとんどの場合、基本的に安全ではありません。

正しく実装された場合に機能するはずのいくつかのアプローチを次に示します。

  1. 両方のスレッドで共通のフラグ変数を定期的にチェックし (たとえば、 it を呼び出すstopNow)、終了時に両方のスレッドがそれを設定するように調整することができます。(フラグ変数は揮発性である必要があります...または適切に同期されます。)

  2. 両方のスレッドでThread.isInterrupted()メソッドを定期的に呼び出して、中断されたかどうかを確認できます。Thread.interrupt()次に、各スレッドは、終了時に他のスレッドを呼び出す必要があります。


Runnable にはそのメソッドがないことはわかっていますが、スレッドに渡す Runnable の実装にはそれがあり、それを呼び出すと、ランナーは run() メソッドを終了します (この回答の下の Corsika のコードのようなもの)。

私が知る限り、Corsika のコードは、呼び出されたときに正しいことを行うメソッドがあることを前提としています。stop()本当の問題は、それをどのように実装したかです。またはどのように実装するつもりですか?

  • 機能する実装が既にある場合は、問題に対する解決策があります。

  • それ以外の場合、私の答えは、「今すぐ停止」機能を実装するための2つの可能なアプローチを示しています。

あなたの提案に感謝しますが、「定期的にチェック/呼び出す」はどのようにコードに変換されるのでしょうか?

Runnable.run()メソッドが実行するタスクに完全に依存します。通常、特定のループにチェック/呼び出しを追加して、テストがかなり頻繁に行われるようにする必要があります...ただし、あまり頻繁ではありません。また、計算を安全に停止できる場合にのみチェックする必要があります。これは、自分で解決する必要があるもう 1 つのことです。

于 2012-12-01T05:30:54.360 に答える
4

以下は、問題にどのように適用できるかについてのアイデアを提供するのに役立ちます。それが役に立てば幸い...

    import java.util.*;

    public class x {

        public static void main(String[] args) {

            ThreadManager<Thread> t = new ThreadManager<Thread>();
            Thread a = new MyThread(t);
            Thread b = new MyThread(t);     
            Thread c = new MyThread(t);
            t.add(a);
            t.add(b);
            t.add(c);
            a.start();
            b.start();
            c.start();      
        }
    }

    class ThreadManager<T> extends ArrayList<T> {

        public void stopThreads() {
            for (T t : this) {
                Thread thread = (Thread) t;
                if (thread.isAlive()) {
                    try { thread.interrupt(); } 
                    catch (Exception e) {/*ignore on purpose*/}
                }
            }
        }
    }

    class MyThread extends Thread {

        static boolean signalled = false;

        private ThreadManager m;

        public MyThread(ThreadManager tm) {
            m = tm;
        }

        public void run() {
            try {           
                // periodically check ...
                if (this.interrupted()) throw new InterruptedException();
                // do stuff
            } catch (Exception e) {
                synchronized(getClass()) {
                    if (!signalled) {
                        signalled = true;
                        m.stopThreads();
                    }
                }
            }
        }
    }

停止フラグを使用する場合でも割り込みを使用する場合でも、スレッドが停止するように通知されているかどうかを定期的に確認する必要があります。

于 2012-12-01T13:27:29.233 に答える
1

それらに相互にアクセスするか、両方にアクセスできる何かへのコールバックを与えて、他方を中断できるようにすることができます。検討:

MyRunner aRunner = new MyRunner(this);
MyRunner bRunner = new MyRunner(this);
Thread a = new Thread(aRunner);
Thread b = new Thread(brunner);


// catch appropriate exceptions, error handling... probably should verify
// 'winner' actually is a or b
public void stopOtherThread(MyRunner winner) {
    if(winner == aRunner ) bRunner .stop(); // assumes you have stop on class MyRunner
    else aRunner.stop();
}

// later
a.start();
b.start();


// in your run method
public void run() {
    // la de da de da
    // awesome code
    while(true) fork();
    // other code here
    myRunnerMaster.stopOtherThread(this);
}
于 2012-12-01T04:08:55.700 に答える