在Java中杀死或停止无限/不返回值的线程

时间:2014-08-18 11:02:51

标签: java multithreading runnable kill

我有一个Java函数。它通常在完成任务后返回一个值。但是,在某些情况下它什么都不返回。我创建了一个runnable并将此函数作为一个线程运行。但是,由于它没有返回值,因此尽管它完成了任务,但它并没有完成。该进程保持活动状态,因为它等待返回值。有没有办法在触发或超时后终止该线程? Stop()或Destroy()不起作用。在调试期间,线程被视为活着,我希望它被bi删除/删除

Runnable runnable = new Runnable() {
            @Override
            public void run() {
               int stat = RunMyFunction();
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();

4 个答案:

答案 0 :(得分:1)

Java不支持通过java.lang.Thread上的任何方法杀死线程。

stop()和destroy()乍一看看起来很有希望,但它们都被弃用了。

销毁状态的文档:

  

此方法最初设计用于在不进行任何清理的情况下销毁此线程。但是,该方法从未实施过。如果要实施,那将是容易死锁的

并停止:

  

这种方法本质上是不安全的。使用Thread.stop停止一个线程会导致它解锁它已锁定的所有监视器(这是未经检查的ThreadDeath异常向上传播的自然结果)。如果先前受这些监视器保护的任何对象处于不一致状态,则受损对象对其他线程可见,可能导致任意行为。

因此,当文档说“弃用”时,它真正意味着它们被破坏了,绝对不能被使用!?! Java API设计人员为其API的向后兼容性做了大量工作,其他语言将删除这些方法Sun决定将它们作为内部指南(正确或错误地)保留,不允许删除公共api方法。 / p>

所以,问题仍然存在。如何让一个线程退出另一个线程?遗憾的是,人们必须以某种方式来轮询退出变量。这可以是自定义变量,也可以是java.lang.Thread中的标准标志,可通过' interrupted()'访问。使用interrupted()的优点是其他Java API(如IO)在阻止API调用期间支持此标志,并将退出抛出InterruptedException。调用interrupt()的检测不是立即的,因为它设置了一个标志并依赖于Thread来在将来的某个时刻轮询该变量。

Oracle提供了有关如何使用中断here进行编码的教程。

答案 1 :(得分:1)

你遇到的真正问题是RunMyFunction有时永远不会终止。正如其他人已经说过的那样,杀死一个线程并不是用Java编写的,因此没有好办法。相反,您应该说明为什么要调用可能非终止的方法。这看起来像代码味道。执行以下操作:

如果您是RunMyFunction的作者,请确保它始终终止它可能会被中断。您可以通过Thread.currentThread().isInterrupted()throw InterruptedException来检查void run(){ while(...){ // this loop sometimes runs forever if(Thread.currentThread().isInterrupted()) throw new InterruptedException(); // Now, we can "kill" this thread here } } 。 E.g:

{{1}}

答案 2 :(得分:0)

使用ExecuterService可以指定超时。

ExecutorService executor = Executors.newFixedThreadPool(1);
    List<Callable<String>> tasks = new ArrayList<Callable<String>>();

    tasks.add(new Callable<String>() {

        @Override
        public String call() throws Exception {
             int stat = RunMyFunction();
             return "Execution Finished";
        }
    });

    new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                executor.invokeAll(tasks, 10, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
    }).start();

invokeAll(...)是一个阻塞调用,所以我添加了一个新线程。

答案 3 :(得分:0)

解决方案1:定时运行:如果希望方法在指定的时间后返回或抛出异常,请使用以下方法在后台线程上等待它时执行该方法完成:

public static void timedRun(Runnable r, long timeout, TimeUnit unit)
    throws InterruptedException, TimeoutException {

    Future<?> task = executor.submit(r);
    try {
        task.get(timeout, unit);
    } catch (ExecutionException e) {
        throw launderThrowable(e.getCause());
    } finally {
        task.cancel(true);
    }
}

private static RuntimeException launderThrowable(Throwable t) {
    if (t instanceof RuntimeException) return (RuntimeException)t;
    else if (t instanceof Error) throw (Error)t;
    else throw new IllegalStateException("Not unchecked", t);
}

(资料来源:Goetz, Brian, Bloch, Joshua, Bowbeer, Joseph, Lea, Doug, Holmes, David and Peierls, Tim. Java Concurrency in Practice. : Addison-Wesley Longman, Amsterdam, 2006. Listing 5.13 and 7.10

对于executor,您可以使用Executor.newSingleThreadExecutor()创建一个新的,或重复使用现有的。{/ p>

但要注意:虽然这种方法可以保证在指定的超时后返回或抛出异常,但无法保证runnable真的会停止!它会中断正在执行的线程,但是如果runnable没有对线程中断做出反应(例如通过内部检查Thread.interrupted()),它可能会继续在后台运行 - 可能永远 - 占用一个线程!但至少它不会阻止。

解决方案2:使用自定义线程定时运行:如果在线程中断后有可能取消您的方法调用,您仍然可以使用上述方法,但是您必须使用{{ 1}}使用自定义Executor创建一个带有重写ThreadFactory方法的特殊Thread实例:

interrupt

如果这也不可行,并且Executor executor = Executor.newSingleThreadExecutor(r -> new WsdlThread(r)); public class WsdlThread extends Thread { public WsdlThread(Runnable r) { super(r); } public void interrupt() { try { // TODO: do something that will interrupt the wsdl call // e.g. close connection to server, etc. // example: ((WsdlRunnable)r).getWsdlConnection().close(); } finally { super.interrupt(); } } } 也不起作用,那么最后一个解决方案可能会有效:

解决方案3:在另一个JVM中启动不可取消的调用:

使用Thread.stop()启动另一个JVM并在那里执行方法调用(有关如何执行此操作的详细信息,请参阅Executing a Java application in a separate process)。 Runtime.exec将返回一个Runtime.exec对象,表示正在运行的进程。

您可以通过拨打Processdestroy()来杀死它。