web-dev-qa-db-ja.com

無限ループを中断する方法

質問するのは少しばかげていると思いますが、それでも技術的な観点についてもっと知りたいと思います。

無限ループの簡単な例:

public class LoopInfinite {
    public static void main(String[] args) {
        for (;;) {
            System.out.println("Stack Overflow");
        }
    }
}

このクラスの外部から(たとえば、継承の助けを借りて)この無限ループを中断(停止)するにはどうすればよいですか?

24
big zero

これを書いても汚い気がしますが….

別のスレッドから、PrintStream実装を使用してSystem.setOut()を呼び出すことができます。これにより、println()を呼び出すとRuntimeExceptionがスローされます。

49
David Grant

volatile変数を使用してこれを実現できます。これは、Threadの外側を変更し、ループを停止します。

   for(;!cancelled;) /*or while(!cancelled)*/{
       System.out.println("Stackoverflow");
   }

これは、無限ループを作成するためのより良い方法です。

public class LoopInfinite{
      private static volatile boolean cancelled=false;
      public static void main(String[] args){
             for(;!cancelled;) { //or while(!cancelled)
                    System.out.println("Stackoverflow");
             }
      }
      public void cancel(){
        cancelled=true;
      }
}
26

canは、別のスレッドから無限ループを実行しているスレッドに到達し、そのスレッドで割り込みを呼び出すことができます。ただし、何をしているのかを十分に確認する必要があり、中断されたスレッドが中断されたときに適切に動作することを期待します。

ここでは、識別しやすいように、問題のあるループでスレッドに名前を付けました。次のソリューションは競合状態に対して脆弱であることに注意してください。

_    Thread loop = new Thread() { 

        public void run() {
            Thread.currentThread().setName("loop");
            while(true) {
                System.out.print(".");
            }
        }
    }.start();
_

次に、他のクラスで:

_    ThreadGroup group = Thread.currentThread().getThreadGroup();
    Thread[] threads = new Thread[group.activeCount()];
    group.enumerate(threads);

    for(Thread t : threads) {
        if(t.getName().equals("loop")) {
            /* Thread.stop() is a horrible thing to use. 
               Use Thread.interrupt() instead if you have 
               any control over the running thread */
            t.stop();
        }
    }
_

私の例では、2つのスレッドが同じThreadGroupにあると想定していることに注意してください。これが当てはまるという保証はないため、さらに多くのグループをトラバースする必要がある場合があります。

これをある程度制御できる場合、ここでの適切なパターンは、ループ宣言の代わりにwhile(!isInterrupted())を使用し、t.interrupt()の代わりにt.stop()を使用することです。

これを投稿した後でも、あなたへの私の唯一のアドバイスは、これをしないことです。あなたできますそれをします、しかしあなたは本当にすべきではありません

6
Joel Westberg

これは不可能だと思います。ループ内でbreakのみを使用します。あなたが使うことができます

while(cond) {}

そして他の場所からそれを作るfalse

5

このスレッド[main]への継承された参照の静的参照を保持することにより、このスレッドを中断できます。このようにThread.currentThread()から要求します。

public class LoopInfinite{
public static Thread main = null;
public static void main(String[] args){
    main = Thread.currentThread();
    for(;;)
       System.out.println("Stackoverflow");
    }
}

そして終了するには、他のスレッドからこれを呼び出すことができます

LoopInfinite.main.interrupt();

ただし、両方のスレッドが同じグループの一部である場合にのみ機能します。それ以外の場合、スレッドを呼び出すと SecurityException

3
Siddharth Tyagi

「無限」ループが必要な場合は、必ずスレッドが必要です(そうでない場合、アプリはループが終了するまでスタックします)。

class BigLoop extends Thread
{

    private boolean _sexyAndAlive = true;

    // make some constructor !

    public void softTerminate()
    {
    _sexyAndAlive = false;
    }


    public void run()
    {
        try
        {
            while( _sexyAndAlive )
            {
               // Put your code here 
            }
        }
        catch( Some Exceptions ... )
        {
            // ...
        }
        // put some ending code here if needed
    }
}


// in another file :

BigLoop worker = new BigLoop();
worker.start(); // starts the thread

// when you want to stop it softly
worker.softTerminate();

したがって、これはバックグラウンドでループを実行する簡単な方法です。

2
Benj

このクラスの外からこれを止めることはできません。継承を使用する場合、ループを上書きできますが、abort-flagがないと上書きできません。

2
rollstuhlfahrer

非常にオープンな質問ですが、そのようなループを停止するには、おそらく別のスレッドから操作する必要があります。次に、他のスレッドは、無限ループが定期的にチェックできる変数を設定する必要があり、変数に特定の値があるかどうかを確認します。ループから抜け出します。

2
Thorbear

プロセスを完全に停止せずに、この特定のループを中断することはできません。一般に、外部ソースから実行しようとしている場合(ブール値などの条件をループ内で簡単に設定できるため、ソースコードを制御できないと想定しています。外部スレッドから)、 スレッドオブジェクト を介してこれを行うかどうかに関係なく、実行中のスレッドを停止する必要があります(たとえば、ループすることによって、何らかの方法でスレッドへの参照を見つける必要があります- 既存のスレッド )、または システムプロセス として停止するかどうか。

もう1つのオプションは、無限ループではないループでメソッドをオーバーライドすることですが、静的メソッドであるため、残念ながらこれは例には適用されません。

2
Thor84no

あなたの種類の問題はスレッドの問題のように見えます。しかし、それでも、スレッドにも停止フラグを含めることをお勧めします

2
IvoC

変数shouldBreakまたはgetterとsetterを使用して設定できるものを追加します。

public class LoopInfinite {
private boolean shouldBreak = false;

public boolean isShouldBreak() {
    return shouldBreak;
}

public void setShouldBreak(boolean shouldBreak) {
    this.shouldBreak = shouldBreak;
}

public static void main(String[] args) {
    // Below code is just to simulate how it can be done from out side of
    // the class
    LoopInfinite infinite = new LoopInfinite();
    infinite.setShouldBreak(true);
    for (;;) {
        System.out.println("Stackoverflow");
        if (infinite.shouldBreak)
            break;
    }
}

}

1
Amit Deshpande

これが私がしたことです:

while(Exit == false){
    Scanner input = new Scanner(System.in);
    String in = input.next();

    switch(in){
        case "FindH": 
            FindHyp hyp = new FindHyp();
            float output = hyp.findhyp();
            System.out.println(output); 
        case "Exit":
            Exit = true;
    break;

    }
  }  
0