13

I am getting IllegalThreadStateException exception when using following code: I have already started this thread once(by using thread.start()) and again trying to start it at another place, so used following code:

thread.interrupt();
thread.start();

But thread.start() is throwing IllegalThreadStateException.

What should I use to solve it?

Vit Khudenko
  • 28,288
  • 10
  • 63
  • 91
AnkitRox
  • 534
  • 1
  • 6
  • 16

2 Answers2

21

Thread objects are only meant to be started once. If you need to stop/interrupt a Thread, and then want to start it again, you should create a new instance, and call start() on it:

thread.interrupt();  // if you need to make sure thread's run() method stops ASAP
thread = new MyThreadSubclass();
thread.start();

From the API docs

IllegalThreadStateException - if the thread was already started.

I know it's not 100% clear that you can't call start() again, even if you previously called interrupt(), but that's the way it works.

If you look at the API docs for standard Java, this issue is more clear.

Nate
  • 31,017
  • 13
  • 83
  • 207
  • Thanks Nate. But when I was trying to use 'thread.interrupt();' It is again showing exception as - **IllegalThreadStateException**. – AnkitRox Nov 24 '12 at 06:30
  • @AnkitRox, the API docs don't show that `interrupt()` throws any exceptions. However, my guess would be that you're calling `interrupt()` even before the 1st time that you run this code. You really would only need to interrupt the thread if it's been started once. So, the 2nd, 3rd, etc. times you want to call `start()`, you might call `interrupt()` right beforehand. You could test `thread.isAlive()` before calling `thread.interrupt()`. If that doesn't work, you need to show some more code (e.g. how you create the Thread object). – Nate Nov 24 '12 at 06:46
  • I have a class as `AsyncUploadQuestionsAndLeads` which is extended by `Thread`. Initializing Thread object by using: `AsyncUploadQuestionsAndLeads uploadThread = new AsyncUploadQuestionsAndLeads(event);` And starting the thread from some other place: `uploadThread.start();` After some time, I am using the code as: `uploadThread.interrupt(); uploadThread.start();` This is my code procedure which I have followed. One more Question is - Does thread stops itself, when it completes it's run block? – AnkitRox Nov 24 '12 at 07:20
  • Please read my answer. You can't call `interrupt()`, and then call `start()` right after that, *on the same instance*. If you are going to call `start()` a second time, you have to create a new instance with `uploadThread = new AsyncUploadQuestionsAndLeads(event)` again. And, yes, the thread essentially stops when the `run()` method completes. After `run()` completes, you cannot call `start()` again on the same instance. You must create a **new** one. – Nate Nov 24 '12 at 09:07
  • Thanks Nate. I was also trying your method. But the problem occurred at that time was, it was start a new thread for the new instance and previous thread was also working. – AnkitRox Nov 24 '12 at 13:53
8

In addition to Nate's answer.

AnkitRox states in his comment:

Thanks Nate. I was also trying your method. But the problem occurred at that time was, it was start a new thread for the new instance and previous thread was also working.

So it looks like the problem is "the thread is still running even if I called interrupt on it". Consider this sample (it is ugly, but enough to show the main idea):

final Thread t = new Thread(new Runnable() {
    public void run() {
        while (true) {
            for (int i = 0; i < 100000000; i++); // simulate some action
            System.out.println("hi, interrupted = " 
                    + Thread.currentThread().isInterrupted());
        }
    }
});
t.start();
new Timer(true).schedule(
    new TimerTask() {
        public void run() {
            t.interrupt();
        }
    },
    1000 // 1 second delay
);

Note, the thread continues to run even after interrupt() has been called. The produced output is:

hi, interrupted = false
hi, interrupted = true
hi, interrupted = true
hi, interrupted = true
...
hi, interrupted = true

Actually the programm never stops unless closed forcefully. So what then the interrupt() does? It just sets the interrupted flag to true. After interrupt() has been called the Thread.currentThread().isInterrupted() starts to return false. And that's all.

Another case is if interrupt() is called while the thread is blocked in an invocation of one of the methods that throw InterruptedException, then that method will return throwing the InterruptedException. And if thread's code just "eats" that exception, then the thread will still continue running, consider a sample:

final Thread t = new Thread(new Runnable() {
    public void run() {
        while (true) {
            System.out.println("hi, interrupted = " 
                    + Thread.currentThread().isInterrupted());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                System.out.println("got InterruptedException");
            }
        }
    }
});
t.start();
new Timer(true).schedule(
    new TimerTask() {
        public void run() {
            t.interrupt();
        }
    },
    1000 // 1 second delay
);

Note, the thread continues to run even after interrupt() has been called. The produced output is:

hi, interrupted = false
got InterruptedException
hi, interrupted = false
hi, interrupted = false
...
hi, interrupted = false

Note, this time interrupted = false even after interrupt() has been called. This is because whenever InterruptedException is caught, the interrupted flag is reset to false.

In Java stopping a thread is cooperative mechanism. Meaning it can not be done without cooperation from the thread itself. Here is the fixed version of the above sample:

final Thread t = new Thread(new Runnable() {
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            System.out.println("hi, interrupted = " 
                    + Thread.currentThread().isInterrupted());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                System.out.println("we've been interrupted");
                // restore the interrupted flag
                Thread.currentThread().interrupt();
            }
        }
    }
});
t.start();
new Timer(true).schedule(
    new TimerTask() {
        public void run() {
            t.interrupt();
        }
    },
    1000 // 1 second delay
);

So the correct approach should be to periodically check the interrupted flag. And if interrupted status is detected then just return ASAP. Another common option is not to use Thread.interrupt() at all, but some custom boolean instead.

Vit Khudenko
  • 28,288
  • 10
  • 63
  • 91