Future.get() 总是会因 InterruptedException 而被中断。

9
我在Java中使用Future.get()时遇到了一个奇怪的问题。它总是返回一个InterruptedException,但奇怪的是异常的原因为null,所以我无法确定是谁中断了我。
更糟糕的是,在调用get()之前,我已经检查了Future要执行的任务是否已经完成。
以下是 responsible for the output below 的代码。f 是 Future,callable 返回一个HashMap,其中 Agent 并不是真正相关的内容。如果有太多的 printlines,请见谅,我只是尽可能提供更多信息。callable 的调用方法目前是一个简单的 System.out.println("Hola soy agente"),正如您将看到的,该语句被打印出来,这意味着 callable 也没有引起异常。
以下是代码:
try
    {
        System.out.println(f.isDone());        //true
        System.out.println(f.isCancelled());   //false
        System.out.println(f.toString());      //FutureTask
        newModdedAgents.putAll(f.get());
    }catch(InterruptedException e)
    {
        System.out.println(f.isDone());        //true
        System.out.println(f.isCancelled());   //false
        System.err.println(e);                 //It is an interruptedException
        System.err.println(e.getCause());     //???? null?
        e.printStackTrace();
    }

输出结果如下

 Hola soy agente
 true
 false
 java.util.concurrent.FutureTask@1c4c94e5
 true
 false
 java.lang.InterruptedException
 null

java.lang.InterruptedException
at     java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1302)
at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:248)
at java.util.concurrent.FutureTask.get(FutureTask.java:111)
at com.pf.simulator.Simulation.simulateStep(Simulation.java:217)
at com.pf.gui.ButtonPanel.doWork(ButtonPanel.java:141)
at com.pf.gui.ButtonPanel$1$1.construct(ButtonPanel.java:198)
at com.pf.gui.SwingWorker$2.run(SwingWorker.java:117)
at java.lang.Thread.run(Thread.java:636)

如果您想查看我将可调用对象提交到线程池的位置...那么这就是代码

    for(Callable<HashMap<Integer, Agent>> c : agentCallables)
    {
        Future<HashMap<Integer,Agent>> future = pool.submit(c);
        agentFutureSet.add(future);
    }

然后我使用迭代器遍历这个Set:

    for(Future<HashMap<Integer, Agent>> f : agentFutureSet)
    try
    {
              //Here goes the code at the beginning
4个回答

13

在调用get()方法之前,您是否检查了线程的中断标志?可以使用Thread.currentThread().isInterrupted()进行检查。

要获取更多信息,请查看Future.get()的javadoc,以了解为什么会抛出InterruptedException异常。


1
太棒了!在执行get()之前被中断了!我以为中断异常来自于提交的可调用对象,它在不同的线程上...如果你能解释一下,我会很感激,不管怎样,问题已经解决了。非常感谢。 - dgrandes
2
通过查看Future的javadoc,您可以在此处了解原因:http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Future.html#get%28%29 。如果等待时 "当前线程被中断",则get会抛出InterruptedException。 - daveb
2
令人惊讶的是,在发布这篇文章之前,我去了那个页面很多次,但不知何故我的大脑就无法将等待线程与此相关联!有趣的是,因为有人也有同样的误解,我经过认真阅读文档后向他们解释了这个问题。在stackoverflow上发布第一篇帖子是一次非常有趣的经历! - dgrandes

8
.get()抛出的裸露的InterruptedException表示当前执行线程(调用.get()的线程)在调用get()之前或在阻塞在.get()时被中断。这与执行器线程或其任务被中断不同。某人或某些东西正在中断您的“主”线程,或者至少是调用.get()的线程。
中断不会随机发生 - 必须有一些代码有意引起中断。只有通过调用Thread.interrupt()才能启动中断,但是有一些标准的Java实用程序在幕后调用此函数,例如Future.cancel(true)ExecutorService.shutdownNow()
据我所知,没有外部跟踪中断原因链或堆栈跟踪的方法。您必须查看源代码以确定可以启动中断的位置,并因此推断出在您的情况下哪些方法调用正在引起中断。

我完全理解它们不是偶然发生的,如果我的话让你误解了,我很抱歉...我想知道的是它发生的地方。混淆的原因在于我以为有人正在中断可调用对象,这是错误的。主线程被中断是完全预料到的,因为它属于模拟器...至少现在我知道那个裸露的InterruptedException是什么意思了。 - dgrandes
1
@dgrandes:好的,我认为你现在完全明白了发生了什么。祝你好运,多线程可能是棘手的问题! :-) - Mike Clark

2

异常的原因是Throwable(方法调用不是异常)

只有在你引起线程中断时,线程才会被中断,它不会随机发生。

如果你真的不知道中断来自哪里并想要忽略它,可以先清除它。调用Thread.interrupted()


我知道它是可抛出的,我是在说callable没有在任何地方抛出异常。很抱歉表达不清楚。无论如何,你调用interrupted()允许从get中获取结果!非常感谢。 - dgrandes

0

这表明正在执行提交的 Callable 的线程被中断。这可能是一个合法的中断(例如,如果 Callable 执行某些阻塞操作,如 Thread.sleep,并通过 Thread.interrupt() 明确地中断),或者可能是 ExecutorService(假设您正在使用此服务)正在通过调用 shutDownNow() 停止。

请问您能否发布用于创建线程池以及实现 Callable 的代码?


实际上,这正是我所想的,即这个中断应该属于提交的Callable,但事实并非如此。Callable中的调用方法代码只是一个println。ExecutorService非常简单明了... - dgrandes
不小心按了回车,抱歉,这个服务非常简单。private ExecutorService pool = Executors.newCachedThreadPool(); 如之前所回答的,问题在于当前线程在提交可调用对象时被中断。仔细阅读文档后发现:“InterruptedException - 如果当前线程在等待时被中断”。这与发生的情况相符,因为当前线程在启动之前处于中断状态,该线程正在等待答案,而不是被提交的可调用对象线程... 我想。 - dgrandes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接