24

Though I know it'll be a bit silly to ask, still I want to inquire more about the technical perspective of it.

A simple example of an infinite loop:

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

How can I interrupt (stop) this infinite loop from outside of this class (e.g., with the help of inheritance)?

Boann
  • 48,794
  • 16
  • 117
  • 146
big zero
  • 610
  • 2
  • 8
  • 16

12 Answers12

49

I feel dirty even writing this, but...

From a different thread, you could call System.setOut() with a PrintStream implementation, which throws a RuntimeException when you call println().

Rody Oldenhuis
  • 37,726
  • 7
  • 50
  • 96
David Grant
  • 13,929
  • 3
  • 57
  • 63
  • 8
    `System.setOut(null)` would suffice. – maba Aug 17 '12 at 08:50
  • But where's the different thread? This is the `public static void main`. From another thread you can simply call `Thread.stop`. – Marko Topolnik Aug 17 '12 at 09:09
  • 1
    @MarkoTopolnik Maybe another class with a `main` method just called the `LoopInfinite.main(null)` or something like that. We don't know, only the OP knows... – maba Aug 17 '12 at 09:13
  • 2
    @maba That' a VERY far-fetched hypothesis. When an asker posts code involving `main`, we can be pretty sure he means that's his entry point. Otherwise, why not assume there's an AOP infrastructure that would allow injecting arbitrary code to every `PrintStream.println` call, or that `System` is actually an `import my.package.System` with a completely unrelated implementation? – Marko Topolnik Aug 17 '12 at 09:15
  • 2
    @Marko I think you're probably looking into the method issue too much. Why not post the Thread.stop as a different answer, including the Thread access. – David Grant Aug 17 '12 at 09:18
  • @MarkoTopolnik I think we can all agree that as the question stands it is very hard to give any true answers at all. This answer is just as good as any of the other answers right now. Otherwise I would suggest you to post that comment of yours on all (currently 12) answers since all of them assume things. – maba Aug 17 '12 at 09:20
  • @maba It's because this is the only answer I really liked and upvoted. But when I like a solution, I also tend to think it through :) Here, since with a different thread available there's really no challenge to it, I see the only challenge in answering under the assumption that there are NO other threads. – Marko Topolnik Aug 17 '12 at 09:29
  • @MarkoTopolnik : for the sake of simplicity, I have posted it with in main() method, you can ignore it for the answer purpose;Thanks to David and maba – big zero Aug 17 '12 at 09:32
  • @bigzero But you did mean the printing part? Since if the thread is stuck in a loop with no printing to `out`, this will not work. The general answer leans towards `Thread.stop`, however be aware of huge potential for problems when calling that. – Marko Topolnik Aug 17 '12 at 09:35
  • 6
    @Marko I hope for the sake of all that is sacred in the programming world that this is a purely academic question. ;) – David Grant Aug 17 '12 at 09:37
  • both,the process as well as the printing part. – big zero Aug 17 '12 at 09:40
  • @DavidGrant Yes, the strongest point of your solution is its humor and out-of-the box thinking, that's why I like it! – Marko Topolnik Aug 17 '12 at 09:42
  • @DavidGrant, thanks for your solution,could you show me in code that how to implement,what you have answered. – big zero Aug 17 '12 at 09:45
  • While the outside the box thinking is good. I dread to think of anyone actually doing this. I think I'd rather write code to modify the byte-code of the offending code to include a boolean check before executing it than do this. – Vala Aug 17 '12 at 09:47
  • @bigzero Now you're being rather lazy, surely? With the info he's given, almost all the code could be auto-generated by an IDE. You only need to add the words `new` and `throw`. In fact, the first comment here shows an alternative with the *full code required*. – Vala Aug 17 '12 at 09:50
  • @big zero: you'll need to spawn another `Thread` before the loop with a `java.lang.Runnable` that executes @maba's code. – David Grant Aug 17 '12 at 09:55
26

We can achieve it using volatile variable, which we will change ouside Thread and stop the loop.

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

This is better way to write Infinite Loop.

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;
      }
}
Xavi
  • 20,111
  • 14
  • 72
  • 63
Subhrajyoti Majumder
  • 40,646
  • 13
  • 77
  • 103
  • 13
    Don't forget to declare cancelled as volatile – Buhb Aug 17 '12 at 08:45
  • 4
    Maybe you would want the `cancel()` method to be `static` too. Then you don't need an object of `LoopInfinite` to be able to stop the loop. – maba Aug 17 '12 at 09:38
  • 2
    @maba - dude u r r8 in this context. This is a snippet not actual implementation. probably there may be thousand changes required for actual implementation. – Subhrajyoti Majumder Aug 17 '12 at 09:41
  • @Buhb: That's not necessary unless you have other memory being read/written to from multiple threads that has to be consistent with the 'cancelled' flag. And if that's your scenario, you're better off using locks/Monitor or other heavyweight concurrency control, because 'volatile' by itself is probably not going to help you. And if you do use locks properly, volatile becomes unnecessary in the majority of cases. Avoid it unless you really understand what you're doing, down to the level of the CLR memory model and what store/release reordering is. Just use locks. – Joren Aug 17 '12 at 13:09
  • @Joren: If I'm not misstaken, the volatile keyword is necessary since one thread is spinning around in the loop, so there will be another thread that updates cancelled, however you have a good point that you should definitely use something more high level here. An AtomicBoolean for instance. – Buhb Aug 18 '12 at 07:25
  • @Buhb: Writes to booleans are already guaranteed to be atomic in .NET. What volatile might do for you is if you do `A = 5; cancelled = true;` in another thread, that it doesn't get reordered to `cancelled = true; A = 5` from the viewpoint of the loop thread, which might be important if you're doing something like `while (!cancelled) { } Console.WriteLine(A);` But for more complicated scenarios, just a volatile won't do, and it's difficult to determine when exactly a volatile will be sufficient. So it's more convenient just to forget about volatile and use a lock, is what I meant. – Joren Aug 18 '12 at 12:46
  • @Joren: The question is tagged Java. – Buhb Aug 18 '12 at 15:41
  • @Buhb: Wow, you're right. The C#-style color coding stackoverflow does is playing tricks on me – Joren Aug 18 '12 at 16:42
  • 1
    Why use any local variables for this, rather than the native interrupt()-support? Simply writing `while(!isInterrupted())` will continue until someone calls the interrupt()-method on the thread. – Joel Westberg Sep 27 '12 at 12:28
6

You can get at the thread running the infinite loop from a different thread and call interrupt on it. You'll have to be very sure what you are doing though, and hope that the interrupted thread will behave properly when interrupted.

Here, I've named the thread with the offending loop for easier identification. Beware that the following solution is vulnerable to race conditions.

    Thread loop = new Thread() { 

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

Then in some other class:

    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();
        }
    }

Note that in my example I assume the two threads are in the same ThreadGroup. There is no guarantee that this will be the case, so you might need to traverse more groups.

If you have some control over this, a decent pattern here would be to have while(!isInterrupted()) instead in the loop declaration and use t.interrupt() instead of t.stop().

My only advice to you, even after posting this, is to not do this. You can do it, but you really shouldn't.

Joel Westberg
  • 2,656
  • 1
  • 21
  • 27
  • 1
    When you call `Thread.currentThread().setName("loop");`, aren't you actually still in the main loop and setting a new name for it? I don't usually override the `start()` method of the `Thread` class. – maba Aug 17 '12 at 09:07
  • I am not sure that your loop will acutally stop. In the loop you will have to do `if (Thread.interrupted()) break;`. You can read about interruption of threads here: http://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html – maba Aug 17 '12 at 09:44
  • Modified to use Thread.stop() instead, since you're right. Wishful thinking on my part to think I could avoid stop() ;) – Joel Westberg Aug 17 '12 at 10:04
5

I think this is not possible. Only using break within the loop. You could use

while(cond) {}

And from some other place make it false

Xentatt
  • 1,264
  • 22
  • 35
3

You can interrupt this thread by keeping its static reference of inherited reference to this Thread [main] by asking from Thread.currentThread(), like this

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

And to terminate you can call this from some other thread

LoopInfinite.main.interrupt();

But it will only work if both threads are part of the same group. Otherwise calling thread will get SecurityException

2

You cannot stop this from outside of this class. If you use inheritance you can overwrite your loop, but without abort-flag you won't be able to do so.

rollstuhlfahrer
  • 3,988
  • 9
  • 25
  • 38
2

Very open question, but stopping such loop would most likely require you to operate from another thread. The other thread would then need to set some variable that your infinite loop can check regularly, and if the variable has a certain value; break out of the loop.

Thorbear
  • 2,303
  • 28
  • 23
2

You won't be able to interrupt this particular loop without halting the process entirely. In general, if you're trying to do it from an external source (I'm assuming you have no control over the source code, because if you did you could easily set a condition in the loop, such as a boolean you could set from an external Thread), you will have to halt the running Thread, whether you do this through the Thread object (you'll have to find a reference to it somehow, for example by looping through existing Threads), or whether you halt it as a system process.

Another option would be to override the method with a loop that isn't an infinite loop, but unfortunately that doesn't apply to your example because it's a static method.

Community
  • 1
  • 1
Vala
  • 5,628
  • 1
  • 29
  • 55
  • for the sake of simplicity,let say,I'm not usin main();in a simple class just this piece of infinite code is written,...then – big zero Aug 17 '12 at 08:49
  • Then if you can't change the code, you'll have to find the Thread it's running in, which could either be by having a reference to it from when it was created, or you could loop through all the Threads there are and try to determine which is the appropriate one, but this might be difficult. If you specify more clearly what exactly the situation is (how is the loop started, what exactly do you need to happen, etc., for example, is the loop started by code you control?) – Vala Aug 17 '12 at 09:43
2

Your kind of problem looks like a Threading problem. But still, it is now a a good practice to include a stopping flag even in threads

IvoC
  • 86
  • 7
2

If you need an "infinite" loop, you sure need a thread (else your app will be stuck until the end of the loop).

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();

So, this is a simple method to have background running loop.

Benj
  • 1,184
  • 7
  • 26
  • 57
  • You can also, if you know approximately how much loops are needed (eg. a few thousands), set a max count : int i=0, maxCount=10000; while(true){doSomething();i++;if(i>maxCount){break;}} // So you will never go beyond 10k loops – Benj Aug 17 '12 at 09:05
1

Add a variable shouldBreak or something which can be set using getter and 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;
    }
}

}

Amit Deshpande
  • 19,001
  • 4
  • 46
  • 72
0

Here is what I did:

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;

    }
  }