停止线程后再次启动会在黑莓设备上引发IllegalThreadStateException异常

13

当我使用以下代码时,我会遇到 IllegalThreadStateException 异常:

我已经通过使用 thread.start() 启动了这个线程一次,并且现在在另一个地方尝试再次启动它,所以使用了以下代码:

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

但是thread.start()抛出了IllegalThreadStateException

我应该使用什么来解决它?


1
刚刚添加了java标签,因为它适用于任何java相关内容。 - Vit Khudenko
@VitKhudenko 实际上它已经有了Java ME。但是,确实还需要Java标签。 - DiLDoST
2个回答

21

Thread 对象只能被启动一次。如果您需要停止/中断一个 Thread,然后再次启动它,您应该创建一个新实例,并在其上调用 start()

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

API文档中指出,如果线程已经启动,则会抛出IllegalThreadStateException异常。

如果您之前调用了interrupt()方法,即使这样仍然不能再次调用start(),这一点可能并不完全清楚,但事实就是如此。

如果您查看标准Java的API文档,则这个问题就更加明确了。


谢谢Nate。但是当我尝试使用'thread.interrupt();'时,它又显示异常- IllegalThreadStateException - AnkitRox
@AnkitRox,API文档没有显示interrupt()会抛出任何异常。但是我猜测你在第一次运行此代码之前就调用了interrupt()。只有在线程已经启动一次后才需要中断线程。所以,在第二次、第三次等想要调用start()的时候,你可以在调用start()之前立即调用interrupt()。你可以在调用thread.interrupt()之前测试thread.isAlive()。如果这不起作用,你需要展示更多的代码(例如,如何创建Thread对象)。 - Nate
我有一个类名为AsyncUploadQuestionsAndLeads,它是由Thread扩展而来的。通过以下方式初始化线程对象:AsyncUploadQuestionsAndLeads uploadThread = new AsyncUploadQuestionsAndLeads(event);并从其他地方启动线程: uploadThread.start();一段时间后,我使用以下代码: uploadThread.interrupt(); uploadThread.start();这是我遵循的代码过程。还有一个问题是-当线程完成其运行块时,它是否会自行停止? - AnkitRox
请阅读我的回答。您不能在同一实例上调用interrupt(),然后立即调用start()。如果您要第二次调用start(),则必须再次使用uploadThread = new AsyncUploadQuestionsAndLeads(event)创建一个新实例。是的,在run()方法完成后,线程基本上会停止。在run()完成后,您不能在同一实例上再次调用start()。您必须创建一个新的实例。 - Nate
谢谢Nate。我也在尝试你的方法。 但是问题出现了,它为新实例启动了一个新线程,而之前的线程仍在工作。 - AnkitRox

9
除了Nate的回答外,
AnkitRox在他的评论中说:
“谢谢Nate。我也在尝试你的方法。但是问题出现在那时候,它会为新实例启动一个新线程,而之前的线程仍然在工作。”
因此,看起来问题是“即使我调用了interrupt,线程仍然在运行”。考虑以下示例(它很丑陋,但足以显示主要思想):
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
);

请注意,即使调用了 interrupt(),线程仍然会继续运行。产生的输出如下:
hi, interrupted = false
hi, interrupted = true
hi, interrupted = true
hi, interrupted = true
...
hi, interrupted = true

实际上,除非强制关闭,否则程序永远不会停止。那么interrupt()有什么作用呢?它只是将中断标志设置为true。在调用interrupt()后,Thread.currentThread().isInterrupted()开始返回false。就是这样。
另一种情况是,在线程被阻塞在抛出InterruptedException的方法之一的调用时调用interrupt(),那么该方法将返回并抛出InterruptedException。如果线程的代码只是“吃掉”了该异常,那么线程仍然会继续运行,考虑下面的示例:
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
);

请注意,即使调用了 interrupt() 方法,线程仍然会继续运行。以下是产生的输出:

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

注意,这一次即使调用了interrupt()interrupted=false。这是因为每当捕获到InterruptedException时,中断标志会被重置为false
在Java中,停止线程是一个协作机制。这意味着它不可能在没有线程自身的合作下完成。以下是上面示例的修复版本:
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
);

因此,正确的方法是定期检查中断标志。如果检测到中断状态,则立即返回。另一个常见选项是根本不使用Thread.interrupt(),而是使用一些自定义布尔值


很好的解释。一点也不丑陋 :) - Nate

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接