Java应用服务器能够销毁线程吗?如果可以,如何实现?

6

在Java中销毁线程已经被弃用(并且根据javadoc没有实现),而中断它只是一个建议,期望线程退出,但可能不会这样做。 (在JVM内部提供任何杀死线程的方式都是令人不安的设计,但我的问题与设计无关。)

Java应用服务器如何卸载应用程序? 它们是否能够以某种方式销毁被卸载的应用程序的线程? 如果可以,那么如何销毁? 如果不行,那么部署的应用程序中的一个带有无限循环的线程可能会使整个应用服务器崩溃,而没有任何干预的可能性吗?

抱歉我没有为此编写测试用例,但我想知道实际发生了什么。

2个回答

11
不提供任何方法在JVM内部终止线程是一个令人不安的设计,但我的问题与设计无关。Java设计师最初尝试解决杀死和挂起线程的问题,但他们遇到了一个根本性的问题,在Java语言的背景下无法解决。问题在于,如果有可能导致共享数据以非原子方式发生变化或者使用wait/notify机制进行同步的线程被强制终止,则无法安全地终止线程。如果在这种情况下实现线程终止,将导致数据结构的部分更新以及其他正在等待未能到达的通知的线程。换句话说,终止一个线程可能会让应用程序的剩余部分处于不确定和破碎的状态。其他允许您终止线程的编程语言/库(例如C、C++、C#)也面临着我上面所描述的同样的问题,即使相关规范/教材没有明确说明这一点。虽然可以终止线程,但要安全地设计和实现整个应用程序是非常困难的,通常很难做到正确。因此,要使Java中的线程终止安全,可能需要以下一些想法:如果JVM实现了Isolates,则可以在子Isolate中启动可能要终止的计算。问题是,正确实现的隔离只能通过消息传递与其他隔离通信,并且它们通常更加昂贵。共享可变状态的问题可以通过完全禁止突变或向Java执行模型添加事务来解决。这两种方法都会从根本上改变Java。等待/通知的问题可以通过使用允许“其他”线程得知其正在交互的线程已经消失的会合或消息传递机制来解决。仍然需要对“其他”线程进行编码以从中恢复。

编辑 - 对于评论的回应。

thread.destroy()并不是出于解决互斥死锁的问题而设计的,因为它旨在释放(打破)所有由被销毁线程拥有的互斥锁。问题在于,在锁被打破后,所保护的数据结构是否处于合理状态并没有得到保证。

如果我正确了解这个话题的历史,Thread.suspend()Thread.delete()等方法确实在Java 1.0实际应用中导致了问题。这些问题非常严重,对于应用程序编写者来说很难处理,因此JVM的设计者们决定最好的做法是弃用这些方法。这不是一个容易做出的决定。

现在,如果您勇敢的话,您确实可以使用这些方法。在某些情况下它们可能是安全的。但是,围绕着已经废弃的方法构建应用程序并不是良好的软件工程实践。


我不是一个热衷于JVM设计的人,但所有关于死锁的争论似乎都是虚构的。禁用这个特性并不会让Java容易产生死锁。我只是对一个锁进行加锁,从未解锁它。 允许使用thread.destroy()确实会引入死锁的新可能性,但为什么我不能杀死一个不持有任何资源的线程(根据程序员或JVM)? - sibidiba
1
@sibida:回到很多年前,我一直使用已弃用的方法来销毁线程,因为我知道销毁这些线程是“安全”的,而且我从未遇到过任何问题... 但是我早就停止了这样做:总有一种方法可以“取消”你控制的线程,无论是通过关闭某个套接字,通过在阻塞队列上放置毒丸,还是通过将某个“shouldExit”布尔值设置为true等。我曾经认为“销毁”确实是必要的,并一直这样做,但现在我不再这样做了。总是有另一种方法对吧?什么情况下会没有办法“干净地”取消一个线程呢? - SyntaxT3rr0r

2

在EJB服务器内,您无法创建自己的线程。

在Web容器(例如Tomcat)中生成线程并不罕见,但您确实应该仔细考虑是否这样做,并确保管理这些线程的生命周期。


1
当一个bean的方法中实现了无限循环时,应用服务器可以做什么?整个应用服务器需要在操作系统级别上重新启动吗? - sibidiba
1
@sibidiba - 是的,就是这样。 - Stephen C

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