我有一个系统,当它接到来自网络服务的电话时启动工作人员。工作程序由ExecutorService启动,正在启动的类实现Runnable。但是,如果工作人员超时,我实际上无法杀死工作人员,这会导致我的系统出现资源问题。
public class MyClass implements Runnable {
public void internalCall() {
logger.info("B-1");
//Some business code which may take too long
// <...>
logger.info("B-2");
}
public void launch() {
// Wrapper
Callable<Object> callable = new Callable<Object>() {
@Override
public Object call() throws Exception {
internalCall();
return null;
}
};
// Submit
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Object> future = executor.submit(callable);
try {
// Wait
future.get(1, TimeUnit.SECONDS);
}
catch (TimeoutException e) {
logger.warn("Timeout");
}
finally {
logger.info("A-1");
executor.shutdownNow();
future.cancel(true);
logger.info("A-2");
}
}
}
如果工作人员超时,我希望得到以下日志消息:
INFO | B-1
WARN | Timeout
INFO | A-1
INFO | A-2
随后服务保持空闲状态,直到另一个工作者请求进入。但是,尽管在ExecutorService和Future上调用了shutdownNow()和cancel(),但工作人员继续:
INFO | B-1
WARN | Timeout
INFO | A-1
INFO | A-2
INFO | B-2
我环顾四周,还有许多关于杀死线程的其他类似问题,一般的共识是你不应该这样做。但是,这是一个可以扩展的类,意图覆盖internalCall() - 意味着我不能依靠internalCall来监控自己并检查Thread.isInterrupted()或类似的东西。
我想通过攻击furure或executor对象来强制从launch()方法中删除东西。
答案 0 :(得分:4)
N.B。
如果某个线程没有响应Thread.interrupt怎么办?
在某些情况下,您可以使用特定于应用程序的技巧。例如, 如果线程正在等待已知套接字,则可以关闭套接字 导致线程立即返回。不幸的是,真的 不是任何一般的技术。 应该注意到 等待线程不响应的所有情况 Thread.interrupt,它也不会响应Thread.stop。这样 案例包括故意拒绝服务攻击和I / O操作 thread.stop和thread.interrupt无法正常工作。 - Java Thread Primitive Deprecation
所以我们学到了什么......在Java中,不要运行第三方代码,而这些代码实际上与主应用程序在同一执行中无法信任。即使Thread.stop确实有效,你仍然有很多其他的东西比没有检查中断状态的线程更糟糕(即代码调用System.exit(0)
)。
我建议您为第三方代码做的事情是:
将第三方代码作为由您运行的评估语言运行,您可以控制其执行。一些例子是:规则语言,如Drools或无逻辑模板语言,如JMustache。
在单独的执行中运行第三方代码,并使用您的操作系统终止进程和IPC,例如用于通信的套接字。
答案 1 :(得分:1)
首先,future.cancel(true)
不会杀死正在运行的线程。它只是试图以礼貌的方式停止执行#34;。
它做什么它或多或少地发送中断信号,就像你在代码中某处调用yourthread.interrupt()
一样。
仅当run()方法中的代码检查中断时,它才会停止处理。因此,在internalCall()
内部,您需要立即检查是否通过调用Thread.interrupted()
来中断线程并停止执行。中断还会通过抛出InterruptedExcepiton来停止sleep(),wait(),IO操作(这就是为什么那些方法抛出这样的异常)。
ExecutorService
使用相同的机制,因此它将尝试中断正在运行的线程,但是,如果您的代码没有检查此类中断,则该线程将继续运行。
由于各种原因,不应该简单地杀死线程(检查java doc for thread.stop()方法以及为什么不推荐使用),以及&#34; universal&#34;通知线程可能它们应该停止工作的方式是中断信号。