我继承的代码是一个服务器,它产生许多不同类型的守护程序线程,这些守护程序线程在它们进入时接收并响应请求。显然,这很危险,需要重构。现在,如果主程序在其中一个守护程序正在处理请求时停止,则该线程可能会在请求中途被杀死并使某些内容处于不一致状态。
但是,有很多线程分布在代码的不同区域。如果在调用关闭时我不得不手动关闭每个线程,那么在不丢失一些模糊守护进程的情况下获得逻辑流程可能会有点麻烦。
我想要做的是拥有一个类似守护程序线程的线程,但我可以将线程的某些部分标记或切换为关键部分;这将完成therad从收获到完成。虽然守护程序阻塞并等待请求,但它的行为类似于守护程序线程,但不会阻止VM关闭,并且如果VM正在关闭,它将立即停止。但是,当线程主动为特定请求提供服务时(线程处于活动状态的一小部分时间),线程将不被杀死,直到它完成并退出它的关键部分。一旦线程完成它的关键部分,它就有资格被杀死。理想的情况是,当没有更多的非守护线程可用的虚拟机将立即开始它的关闭过程中,即使一些后台程序仍然在做重要的工作,通过收割任何守护程序不处于临界状态,然后等待其余每个“服务”退出这是关键点,所以它可能被杀死。
有没有一种简单的方法来通过实例化一个Thread类(可能是我编写的一个)或设置一个布尔值来获得这种行为,而不是必须显式地编写每个线程来正确处理中断,使其表现得像这样?我正在寻找一种大多数以白痴为标准的方法,这样如果在这样的线程中运行的插件没有被写入以完全处理中断,那么线程仍将正常完成它的关键部分,然后在VM关闭时退出。
答案 0 :(得分:5)
但是,有很多线程分布在代码的不同区域。如果在调用关闭时我不得不手动关闭每个线程,那么在不丢失一些模糊守护进程的情况下获得逻辑流程可能会有点麻烦。
不幸的是,这样做的最好方法就是暗示。你应该在分叉线程的类上有一个destroy()
方法,以便它们可以自己明确地清理。但这确实需要有人在应用程序终止时调用那些destroy方法。
我想要做的是拥有一个类似守护程序线程的线程,但是有一个关键部分,它在完成之前不能被杀死(或者如果它需要太长时间可能会超时?)。
Java线程中没有任何内容允许此行为。一个线程是守护进程,或者它不是,并且在线程开始之前设置。
通过实例化类或设置布尔
,是否有一种简单的方法来获取此行为
我认为你在这里做点什么。我会有一个ThreadUtils
类,其中包含volatile boolean shutdown
字段。
public class ThreadUtils {
private static volatile boolean shutdown = false;
/** called by main when the application is shutting down */
public static void shutdown() {
shutdown = true;
}
/** used by the various non-daemon threads to test for shutdown */
public static boolean isShutdown() {
return shutdown;
}
}
您的主程序会将shutdown标志设置为true,然后您的所有线程都需要在其代码中检查此布尔值:
// we can test for shutdown only at "appropriate" points in the thread
while (!ThreadUtils.isShutdown()) {
...
// we are not ready to be killed here
...
}
像这种模式,虽然有点粗糙,听起来像是满足了你的要求。
答案 1 :(得分:1)
我正在努力改善@Gray的最后答案。
您可以维护当前正在运行的线程的计数器。每个新线程启动都将递增此计数器,并且每个完成run()
的线程将递减它。然后,您可以使用API Runtime.addShutdownHook()
在主线程中添加关闭挂钩。当java进程被指示退出时,此挂钩将全局标志ThreadUtils.isShutdown()
的条件设置为true并等待所有正在运行的线程完成工作并在所有线程退出时自然死亡。
为了防止无限期等待,你可以在shutdown hook的run()
方法中超时。如果发生超时,run()
将立即终止,导致所有守护程序线程也终止。
答案 2 :(得分:0)
因此所有这些守护程序线程都是处理请求的事件循环。如果您只是向所有人发送关闭请求,那么他们可以合作退出。每个线程可能都有一个特殊的方法来从某个地方轮询请求,所以你需要稍微重构它们。