【问题标题】:killing an infinite loop in java在java中杀死一个无限循环
【发布时间】:2011-03-30 04:51:30
【问题描述】:

我正在使用第三方库来处理大量数据集。该过程偶尔会进入无限循环(或被阻止 - 不知道为什么并且无法进入代码)。我想在设定的时间后杀死它并继续下一个案例。一个简单的例子是:

for (Object data : dataList) {
    Object result = TheirLibrary.processData(data);
    store(result);
}

processData 通常最多需要 1 秒。我想设置一个计时器,它会在 10 秒后杀死 processData()

编辑 我会很感激一个代码 sn-p (我没有使用线程练习)。 Executor 方法看起来很有用,但我不太清楚如何开始。此外,更传统方法的伪代码对我来说太笼统了。

@Steven Schlansker - 建议除非第三方应用程序预期中断,否则它将无法工作。再次详细说明和示例将不胜感激

编辑 我从同事 Sam Adams 那里得到了我想要的精确解决方案,我将其附加为答案。它比其他答案更详细,但我会给他们两个投票。我会将 Sam 标记为已批准的答案

【问题讨论】:

  • 肯定是死循环了,还是被阻塞了?分析封闭的库可能会有所帮助(除非它被混淆了)。
  • @Jim Downing 是的,它可能被阻止 - 不知道为什么
  • 这可以在 JMX 中完成吗?

标签: java kill infinite-loop


【解决方案1】:

ExecutorService.invokeAll(...) 方法之一采用超时参数。创建一个调用库的 Callable,并将其包装在 List 中作为该方法的参数。返回的 Future 表明它是如何进行的。

(注:未经我测试)

【讨论】:

  • 给这个+1,因为这是我要写的方法。可能可以用一些代码来解释它是如何工作的。但绝对使用 java.util.concurrent 是这样做的方法。
  • 欢迎写出更好的答案。
  • 如果库不能很好地处理中断,你可能仍然永远不会从无限循环中返回。 :-(
  • @Steven Schlansker 处理此问题的唯一安全方法是启动一个单独的 jvm 并使用 RMI 调用该方法。这样你就可以杀死另一个 jvm。
  • @Steven - 每个 Java 程序员都应该学会安全处理中断的论点。
【解决方案2】:

将对库的调用放在另一个线程中,并在超时后终止该线程。这样,如果它们不相互依赖,您也可以同时处理多个对象。


编辑:演示代码请求

这是伪代码,因此您必须对其进行改进和扩展。错误检查天气呼叫是否成功也会有所帮助。

for (Object data : dataList) {
    Thread t = new LibThread(data);
    // store the thread somewhere with an id
    // tid and starting time tstart 
    // threads
    t.start();
    }

while(!all threads finished)
{
    for (Thread t : threads)
    {
        // get start time of thread
        // and check the timeout
        if (runtime > timeout)
        {
            t.stop();
        }
    }
}

class LibThread extends Thread {
    Object data;

    public TextThread(Object data) 
    {
        this.data = data;
    }

    public void processData() 
    {
        Object result = TheirLibrary.processData(data);
        store(result);
    }
}

【讨论】:

  • 你打败了我 - 我已经删除了我的类似答案,但我认为值得一提的是,通过使用 join(timeout) 你将等待足够长的时间......
【解决方案3】:

Sam Adams 给我发了以下答案,这是我接受的答案

Thread thread = new Thread(myRunnableCode);
thread.start();
thread.join(timeoutMs);
if (thread.isAlive()) {
  thread.interrupt();
}

myRunnableCode 定期检查Thread.isInterrupted(),如果返回true,则干净退出。

您也可以这样做:

Thread thread = new Thread(myRunnableCode);
thread.start();
thread.join(timeoutMs);
if (thread.isAlive()) {
  thread.stop();
}

但这种方法已被弃用,因为它很危险。

http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Thread.html#stop() “这种方法本质上是不安全的。使用 Thread.stop 停止线程会导致它解锁它已锁定的所有监视器(这是未经检查的 ThreadDeath 异常在堆栈上传播的自然结果)。如果以前受保护的任何对象这些监视器处于不一致的状态,损坏的对象对其他线程可见,可能导致任意行为。”

我已经实现了第二个,它做了我目前想要的。

【讨论】:

  • 第二个解决方案(您说您已经实现)与添加到 schoetbi 的答案中的解决方案和评论相同。
  • @Jim Downing schoetbi 的回复是伪代码,没有给出准确的调用(例如“while(!all threads finished)”没有给出实际的方法
猜你喜欢
  • 2013-08-04
  • 1970-01-01
  • 2016-10-26
  • 2014-05-07
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
  • 2021-01-05
  • 1970-01-01
相关资源
最近更新 更多