停止线程并再次开始在黑莓中给出 IllegalThreadStateException

Posted

技术标签:

【中文标题】停止线程并再次开始在黑莓中给出 IllegalThreadStateException【英文标题】:Stop thread and again start giving IllegalThreadStateException in blackberry 【发布时间】:2012-11-12 09:13:35 【问题描述】:

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

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

但是thread.start() 正在抛出IllegalThreadStateException

我应该用什么来解决它?

【问题讨论】:

刚刚添加了java标签,因为它对任何java都是通用的。 【参考方案1】:

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

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

From the API docs

IllegalThreadStateException - 如果线程已经启动。

我知道你不能再拨打 start() 并不是 100% 明确的,即使你之前拨打了 interrupt(),但它就是这样工作的。

如果你看API docs for standard Java,这个问题就更清楚了。

【讨论】:

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

除了 Nate 的回答。

AnkitRox 在他的评论中说:

谢谢内特。我也在尝试你的方法。但是当时出现的问题是,它为新实例启动了一个新线程,并且之前的线程也在工作。

所以看起来问题是“即使我调用了中断,线程仍在运行”。考虑这个示例(它很丑,但足以展示主要思想):

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

注意,这一次 interrupted = false 即使在 interrupt() 已被调用之后。这是因为每当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(),而是使用some custom boolean instead。

【讨论】:

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

以上是关于停止线程并再次开始在黑莓中给出 IllegalThreadStateException的主要内容,如果未能解决你的问题,请参考以下文章

在黑莓中无延迟播放音频

如何在黑莓中运行工作灯的本机代码[关闭]

是否可以使用 MapField 在黑莓中移动地图。

如何在黑莓中使用经度和纬度获取当前地址

如何在黑莓中裁剪具有特定形状的图像?

如何防止应用程序在黑莓中启动