18

マルチスレッドのJavaプロジェクトがあり、実行中のすべてのスレッドを停止するメソッドstop()を追加したいと思います。問題は、このプロジェクトが他の誰かによって開発されていることであり、私はそれが複数のスレッドを実装する方法に精通していません。

私が知っているのは、プロジェクトが開始されると、多くのスレッドが呼び出され、それらが永久に実行されるということです。実行中のすべてのスレッドを見つけて停止する方法はありますか?私はたくさん検索し、実行中のスレッドのリストを取得する方法を見つけました:

Set<Thread> threadSet = Thread.getAllStackTraces().keySet();

実行中のすべてのスレッドを停止するには、次に何をしますか?

これらのスレッドを停止したい理由は、このプロジェクトをバンドルとしてOSGiコンテナーにデプロイする必要があるためです。バンドルが開始されると、複数のスレッドが永久に実行されます。したがって、バンドルのライフサイクルを制御するためにすべてのスレッドを停止するために、destroy()メソッドを実装する必要があります。

どうですか

for (Thread t : Thread.getAllStackTraces().keySet()) 
{  if (t.getState()==Thread.State.RUNNABLE) 
     t.interrupt(); 
} 

for (Thread t : Thread.getAllStackTraces().keySet()) 
{  if (t.getState()==Thread.State.RUNNABLE) 
     t.stop(); 
}
4

3 に答える 3

21

これは危険な考えです。のJavadocは次のようにThread.stop()説明しています。

この方法は本質的に安全ではありません。Thread.stopを使用してスレッドを停止すると、ロックされているすべてのモニターのロックが解除されます(チェックされていないThreadDeath例外がスタックに伝播するのは当然の結果です)。これらのモニターによって以前に保護されていたオブジェクトのいずれかが一貫性のない状態にあった場合、損傷したオブジェクトが他のスレッドに表示され、任意の動作が発生する可能性があります。stopの多くの使用法は、ターゲットスレッドの実行を停止する必要があることを示すために変数を変更するだけのコードに置き換える必要があります。ターゲットスレッドはこの変数を定期的にチェックし、変数が実行を停止することを示している場合は、実行メソッドから整然と戻る必要があります。ターゲットスレッドが長期間(たとえば、条件変数で)待機する場合は、割り込みメソッドを使用して待機を中断する必要があります。

基本的に、スレッドは安全に終了するように構築および設計する必要があり、任意のスレッドを安全に強制終了することはできません。かなり標準的なパターンは次のように実装されます。

public abstract class StoppableRunnable implements Runnable {
    private volatile boolean stopWork;
    private boolean done;

    public final void run() {
        setup();
        while(!stopWork && !done) {
            doUnitOfWork();
        }
        cleanup();
    }

    /**
     * Safely instructs this thread to stop working,
     * letting it finish it's current unit of work,
     * then doing any necessary cleanup and terminating
     * the thread.  Notice that this does not guarentee
     * the thread will stop, as doUnitOfWork() could
     * block if not properly implemented.
     */
    public void stop() {
        stopWork = true;
    }

    protected void done() {
        done = true;
    }

    protected void setup() { }
    protected void cleanup() { }

    /**
     * Does as small a unit of work as can be defined
     * for this thread.  Once there is no more work to
     * be done, done() should be called.
     */
    protected abstract void doUnitOfWork();
}

あなたは、あなたがこれらのスレッドの作成者ではないことを暗示しています。これは、それらが安全に停止できない可能性があることを示唆しています。このような場合、Thread.interrupt()スレッドに実行を停止するように指示するために呼び出すことができます(上記のパターンの代わりに、Thread.interrupt()同様の効果を使用できます)が、同様に、スレッドの設計者が割り込みを処理するように記述していない場合、これは何もしないでください。また、一貫性のない状態やその他のエラーを引き起こさないでください。

最終的にThread.stop()は、「[強制]スレッドの実行を停止する」だけで、スレッドの実装を変更できない場合に必要なものです。ただしkill、Unixで使用する場合と同様に、これは危険な提案です。この方法でスレッドを終了した後は、基本的にJVMが不安定で修復不可能な状態にあると見なし、その後できるだけ早くプログラムを終了するようにしてください。


中断してから停止するという提案について:

ここにはまだ多くの問題があります。特に、割り込みはスレッドがすぐに割り込みを行うことを保証するものではなく(明示的ではありませんが、StoppableRunnable上記と同様に機能します)、代わりにスレッドが可能な場合に割り込みを行うフラグを設定します。これは、呼び出しが可能Thread.interrupt()であり、スレッドが適切な割り込み処理動作を開始し、その途中で呼び出しがThread.stop()発生し、スレッドが激しく強制終了され、JVMが破損する可能性があることを意味します。Thread.interrupt()スレッドがその割り込みにいつ、どのように応答するかについての保証を提供しないための呼び出し。これが、の明示的な動作を好む理由StoppableRunnableです。言うまでもなく、電話をかける場合は、最初Thread.stop()に電話することで得られるものはほとんどありません。Thread.interrupt()私はそれをお勧めしませんが、あなたはただ電話したほうがいいでしょうThread.stop()そもそも。

さらに、ループを実行しているコード自体がスレッド内にあることを認識してください。つまり、ループが最初にそれ自体を強制終了し、他のすべてのスレッドを実行したままにする可能性があります。

于 2013-03-25T20:57:27.743 に答える
1

私はこのコードを使用しました:

package com.xxx;

import com.xxx.tools.messageLog;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Mostafa Nazari
 */
public class ProcessAgent extends Thread{

    public ProcessAgent() {
        super("Process-Agent");
    }


    @Override
    public void run() {
        try {
            com.xxx.Process.agent.Main.main(new String[]{});
        } catch (Exception ex) {
            if (ex instanceof InterruptedException) {
                messageLog.stdwar("Process Agent Stopped");
            }else {
                messageLog.stderr("FATAL Error: "+ex.getMessage());
                Logger.getLogger(ProcessAgent.class.getName()).log(Level.SEVERE, null, ex);            
            }
        }    
    }

    public void terminate() {
        if (super.isAlive()) {
            ThreadGroup group = super.getThreadGroup();
            while (group != null) {
                group .interrupt();
                group = super.getThreadGroup();
            }
            super.interrupt();
        }
    }

    public String getStatus() {
        if (super.isAlive()) {
            return "running";
        } else {
            if (super.isInterrupted()) 
                return "stopping";
            else
                return "stopped";
        }
    }

}

この問題に役立つことを願っています

于 2013-12-06T09:45:31.160 に答える
0

通常のAPIを作成する代わりに、ExecutorServiceThreadPoolExecutorThreadなどの高度な並行APIを使用します

この投稿でさまざまなAPIを見ることができます:

JavaのFork/Join vs ExecutorService-いつどちらを使用するのですか?

ExecutorServiceの強制シャットダウンについては、以下のSEの質問を参照してください。

javaExecutorServiceを強制的にシャットダウンする方法

于 2016-05-11T14:52:59.810 に答える