当前位置: 首页 > 知识库问答 >
问题:

Java:杀死ExecutorService作为可运行线程启动的线程

翟善
2023-03-14

我有一个系统,当它收到来自webservice的调用时启动workers。Worker由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(),worker仍继续:

INFO | B-1
WARN | Timeout
INFO | A-1
INFO | A-2
INFO | B-2

我环顾四周,发现还有许多关于杀死线程的类似问题,普遍的共识是不应该这样做。然而,这是一个可以扩展的类,其目的是重写internalCall()——这意味着我不能依赖internalCall来监控自身和检查线程。isInterrupted()或类似的内容。

我只想通过攻击furure或executor对象来强制从launch()方法杀死东西。

共有2个答案

陆展
2023-03-14

首先,未来。取消(true)不会终止正在运行的线程。它只是试图以“礼貌的方式”停止处决。

它的作用是或多或少地发送中断信号,就像您在代码中某处调用yourthread.interrupt()一样。

只有当run()方法中的代码检查中断时,它才会停止处理。因此,在您的internalCall()中,您需要不时检查线程是否未被调用线程中断。中断()并停止执行。中断还将通过抛出InterruptedExceptan停止sleep()、wait()、IO操作(这就是为什么这些方法会抛出这样的异常)。

ExecutorService使用相同的机制,因此它将尝试中断正在运行的线程,但同样,如果代码未检查此类中断,线程将继续运行。

由于各种原因,不应简单地终止线程(检查java文档中的thread.stop()方法以及为什么不推荐该方法),通知线程可能应该停止工作的“通用”方法是中断信号。

公孙宗清
2023-03-14

N、 B。

如果线程不响应Thread.interrupt?

在某些情况下,可以使用特定于应用程序的技巧。例如,如果一个线程正在等待一个已知的套接字,则可以关闭该套接字以使线程立即返回。不幸的是,实际上没有任何技术可以在一般情况下起作用。应该注意的是,在等待线程不响应线程的所有情况下。中断,它不会响应线程。停止任何一个。此类情况包括蓄意拒绝服务攻击,以及针对哪个线程的I/O操作。停止并穿线。中断无法正常工作。-Java线程原语弃用

那么我们学到了什么。。。在Java中,不要运行第三方代码,因为这些代码与主应用程序的执行是不可信任的。即使是Thread。stop do work你还有一大堆比不检查中断状态的线程糟糕得多的事情(即代码html" target="_blank">调用系统。退出(0))。

我建议您对不信任的第三方代码执行以下操作之一:

>

  • 将第三方代码作为由您控制其执行的Java运行的评估语言运行。一些示例是:Drools等规则语言或JMustache等无逻辑模板语言。

    在单独的执行中运行第三方代码,并使用您的操作系统终止进程和IPC,如用于通信的套接字。

  •  类似资料:
    • 问题内容: 如何java.lang.Thread用Java 杀死A ? 问题答案: 有关他们为何不赞成使用Sun的内容,请参见此主题。它详细介绍了为什么这是一种不好的方法,以及通常应该采取什么措施才能安全地停止线程。 他们建议的方式是使用共享变量作为标志,要求后台线程停止。然后可以由另一个请求线程终止的对象来设置此变量。

    • 我有一个工作正常的GUI类,但是我在那个GUI类中有一个按钮,应该是从另一个类打开一个新的GUI... 然而,当调用新的GUI类(newGui)时,它只是一个透明窗口。这是因为两个GUI不能同时运行吗? 我现在正试图以线程的形式打开新的GUI,但我不知道该怎么做! 公开无效运行(); 这是我的尝试,但不出所料,这没有成功。 有什么帮助吗? 谢谢

    • 我正在尝试运行这个简单的类,并且对于每个cicle,我正在计算java进程线程的数量。 ps huH p pid wc-l。 对于每个cicle,线程数是availableProcessors()数的增加。 当ExecutorService在其他线程中运行时,garbace收集器似乎不会释放僵尸线程。 如果我创建了一个静态ExecutorService,它就不会发生

    • 问题内容: 我有一个简单的程序,可以测试当模块不存在时是否能够引发异常。 有时我喜欢在另一个模块中使用此代码: 令人惊讶的是,当我以这种方式运行它时,它不起作用: 这种情况在Ubuntu中发生,并且在干净的CentOS 7.3中也发生。 问题答案: 您正在遇到“导入锁定”。 该文档提到了线程期间导入的限制,您违反了第一个限制(强调我的意思): 虽然导入机制是线程安全的,但是由于提供线程安全的方式存

    • 问题内容: 我有一个程序’foo’运行不同的线程,fooT1,fooT2,.. fooTn。 现在,如果我想编写另一个程序“ bar”,它可能会杀死线程fooTr,那可能吗? 原因:fooTr线程之一跟踪产品许可证。如果该线程被杀死;可能会无限期地运行此产品。杀死’foo’本身可以容忍为’foo’,因为这正是许可证到期时所做的事情。 系统:Linux的Fedora发行 注:用于启动JVM和程序fo

    • 问题内容: 我正在使用命令在UNIX中查看JVM的线程转储。但是在哪里可以找到此命令的输出?我搞不清楚了!! 问题答案: 您也可以使用jstack(JDK附带)进行线程转储并将输出写入所需的任何位置。在Unix环境中不可用吗?