Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop thread and again start giving IllegalThreadStateException in blackberry

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?

like image 402
AnkitRox Avatar asked Nov 24 '12 05:11

AnkitRox


2 Answers

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.

like image 191
Nate Avatar answered Oct 19 '22 13:10

Nate


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.

like image 24
Vit Khudenko Avatar answered Oct 19 '22 13:10

Vit Khudenko