4

我继承的代码是一个服务器,它产生许多不同类型的守护线程,这些线程在请求​​进入时接收和响应。显然,这很危险,需要重构。就像现在一样,如果主程序在其中一个守护进程正在为请求提供服务时停止,则线程可能会在请求中途被终止,并使某些东西处于不一致的状态。

但是,有很多线程分布在代码的不同区域。如果在调用关闭时我必须手动关闭每个线程,那么在不遗漏一些晦涩的守护进程的情况下获得完美的逻辑流程可能会有点痛苦。

我想做的是拥有一个类似于守护线程的线程,但我可以将线程的某些部分标记或切换为关键部分;这将完成从收割到完成的therad。当守护进程阻塞并等待请求时,它的行为就像一个守护线程,不会阻止虚拟机关闭,如果虚拟机关闭,它将立即停止。但是,当线程主动为特定请求提供服务时(线程处于活动状态的时间的一小部分),线程不会被杀死,直到它完成并退出它的关键部分。一旦线程完成它的关键部分,它就有资格被杀死。理想情况下,当没有更多的非守护线程可用时,VM 会立即启动它的关闭进程,即使某些守护进程仍在做关键工作,通过获取任何不处于关键状态的守护进程,然后等待每个剩余的“守护进程”退出这是关键点,所以它可能会被杀死。

有没有一种简单的方法来获得这种行为,只需实例化一个线程类(可能是我写的)或设置一个布尔值,而不是必须显式地编写每个线程来正确处理中断以表现得像这样?我正在寻找一种最愚蠢的证明方式,这样如果在这样的线程中运行的插件没有被编写为完美地处理中断,那么线程仍将正确地完成它的关键部分,然后在 VM 关闭时退出。

4

3 回答 3

5

但是,有很多线程分布在代码的不同区域。如果在调用关闭时我必须手动关闭每个线程,那么在不遗漏一些晦涩的守护进程的情况下获得完美的逻辑流程可能会有点痛苦。

不幸的是,最好的方法就是你暗示的那样。您应该destroy()在派生线程的类上有一个方法,以便它们可以在自己之后显式清理。但这确实需要有人在应用程序终止时调用这些销毁方法。

相反,我想做的是拥有一个类似于守护线程的线程,但有一个特定的关键部分,在它完成之前不能被杀死(或者如果花费太长时间可能会超时?)。

Java 线程中没有任何东西允许这种行为。线程要么是守护进程,要么不是,这是在线程启动之前设置的。

有没有一种简单的方法可以通过实例化一个类或设置一个布尔值来获得这种行为

我认为你在这里有所作为。我会有一个ThreadUtilsvolatile 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;
     }
 }

您的主程序会将关闭标志设置为 true,然后您的所有线程都需要在其代码中检查此布尔值:

 // we can test for shutdown only at "appropriate" points in the thread
 while (!ThreadUtils.isShutdown()) {
     ...
     // we are not ready to be killed here
     ...
 }

像这种模式的东西,虽然有点恶心,但听起来它满足了你的要求。

于 2013-09-20T17:41:34.377 回答
1

我正在尝试改进@Gray 的最后一个答案。

您可以维护当前正在运行的线程的计数器。每个新线程启动都会增加这个计数器,每个线程完成run()都会减少它。然后,您可以使用 API 在主线程中添加关闭挂钩Runtime.addShutdownHook()。当java进程发出退出信号时,该钩子会将全局标志的条件设置为ThreadUtils.isShutdown()true,并等待所有正在运行的线程完成工作,并在所有线程退出后自然死亡。

为防止无限期等待,您可以在关闭钩子的run()方法中设置超时。如果发生超时,run()将立即终止,导致所有守护线程也终止。

于 2013-09-20T17:54:22.887 回答
0

所以所有这些守护线程都是事件循环处理请求。如果您只是向他们所有人发送关闭请求,那么他们可以合作退出怎么办。每个线程可能都有一种从某个地方轮询请求的特殊方式,因此您需要对它们进行一些重构。

于 2013-09-20T18:03:37.220 回答