多线程为什么不能重新启动Java线程对象?
我知道不可能重新启动一个使用过的Java线程对象,但我找不到一个解释为什么这是不允许的;即使保证线程已经完成(参见下面的示例代码)
我不明白为什么start()
(或者至少一个restart()
)方法不能以某种方式将线程对象的内部状态(无论它们是什么)重置为新创建的线程对象时的相同值
示例代码:
class ThreadExample {
public static void main(String[] args){
Thread myThread = new Thread(){
public void run() {
for(int i=0; i<3; i++) {
try{ sleep(100); }catch(InterruptedException ie){}
System.out.print(i+", ");
}
System.out.println("done.");
}
};
myThread.start();
try{ Thread.sleep(500); }catch(InterruptedException ie){}
System.out.println("Now myThread.run() should be done.");
myThread.start(); // <-- causes java.lang.IllegalThreadStateException
} // main
} // class
# 1 楼答案
我的猜测是线程可能直接绑定到实际的本地资源上(出于效率或其他限制),这些资源可能在某些操作系统中可重新启动,但在其他操作系统中不可重新启动。如果Java语言的设计者允许重新启动线程,他们可能会限制JVM可以运行的操作系统的数量
想想看,我想不出一个操作系统允许线程或进程在完成或终止后重新启动。当一个进程完成时,它就死了。如果您想要另一个,请重新启动它。你永远不会复活它
除了底层操作系统强加的效率和限制问题外,还有分析和推理问题。当事物要么是不可变的,要么是离散的、有限的生命周期时,您可以对并发性进行推理。就像状态机一样,它们必须有一个终端状态。它开始了,等待着,结束了吗?如果你允许线程复活,这类事情就不容易解释了
<>你还必须考虑线程复活的含义。重新创建它的堆栈,它的状态,是否可以安全地恢复?你能复活一条异常终止的线吗?等等太多毛,太复杂。所有这些都是为了微不足道的利益。最好将线程保留为不可恢复的资源
# 2 楼答案
您可以通过使用
java.util.concurrent.ThreadPoolExecutor
或手动使用一个线程来解决这个问题,该线程在给定的每个Runnable
上调用Runnable.run()
,而不是在完成时实际退出这并不完全是您所要问的,但是如果您担心线程构造时间,那么它可以帮助解决这个问题。下面是手动方法的一些示例代码:
显然,这只是一个例子。它需要更好的错误处理代码,也许还需要更多的调优
# 3 楼答案
因为他们不是那样设计的。从清晰的角度来看,这对我来说是有意义的。线程表示执行线程,而不是任务。当执行线程完成时,它已经完成了它的工作,如果它再次从顶部开始,它就会把事情搞得一团糟
另一方面,Runnable表示一个任务,可以根据需要多次提交给多个线程
# 4 楼答案
为什么不创建一个新线程?如果您担心创建MyThread对象的开销,请将其设置为可运行,并使用
new Thread(myThread).start();
运行它# 5 楼答案
我会提出另一个问题-为什么线程对象应该是可重启的
可以说,对一个只执行给定任务一次,然后永久完成的线程进行推理(并可能实现)要容易得多。重新启动线程需要一个更复杂的视图,了解程序在给定时间处于何种状态
因此,除非你能想出一个具体的理由,说明重新启动一个给定的
Thread
比仅仅用相同的Runnable
创建一个新的Runnable
更好,否则我认为设计决策是更好的(这与关于可变变量与
final
变量的争论大致相似——我发现最终的“变量”更容易推理,更愿意创建多个新的常量变量,而不是重用现有变量。)# 6 楼答案
Java线程遵循基于以下状态图的生命周期。一旦线程处于最终状态,它就结束了。这就是设计