Future.get() всегда прерывается InterruptedException

У меня СТРАННАЯ проблема с Future.get() в Java. Он всегда возвращается с InterruptedException, однако странно то, что причина Exception равна null, поэтому я не могу сказать, кто меня прервал.

Ситуация становится еще хуже, потому что я проверяю перед вызовом get(), а работа, которую должен выполнить Future, уже выполнена.

Вот код, отвечающий за вывод ниже. f — это Future, а вызываемый объект возвращает HashMap, где Agent не имеет значения. Извините, если слишком много строк для печати, я просто пытаюсь дать как можно больше информации. Метод вызова из callable на данный момент представляет собой простой System.out.println("Hola soy agente"), который, как вы увидите, выводится на печать, а это означает, что вызываемый объект также не вызывал исключения.

Вот код:

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);
    }

и после этого я перебираю этот набор с помощью

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

person dgrandes    schedule 24.11.2010    source источник


Ответы (4)


Вы проверили флаг прерывания потока перед вызовом get()? Вы можете сделать это с помощью Thread.currentThread().isInterrupted().

Для получения дополнительной информации см. javadoc для Future.get(), чтобы понять, почему возникает InterruptedException.

person daveb    schedule 24.11.2010
comment
Это было блестяще! Он был прерван перед get()! Я думал, что прерванное исключение исходит из отправленного вызываемого объекта, который был в другом потоке... если вы можете объяснить, я был бы признателен, в любом случае, это сделало это. Большое спасибо. - person dgrandes; 24.11.2010
comment
Вы можете понять почему, просмотрев javadoc для Future здесь: download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ get выдает InterruptedException, если текущий поток был прерван во время ожидания - person daveb; 24.11.2010
comment
Невероятно, но я заходил на эту страницу много раз, прежде чем опубликовать здесь, и почему-то мой мозг просто не сообразил, что ожидающая тема была именно этой! Забавно, потому что у кого-то еще было такое же заблуждение, и я объяснил им то же самое после ВНИМАТЕЛЬНОГО прочтения документации на этот раз. Это был очень забавный первый опыт публикации на stackoverflow! - person dgrandes; 24.11.2010

Пустой InterruptedException, выброшенный из .get(), указывает, что текущий поток выполнения (поток, вызывающий .get()) был прерван перед вызовом get() или заблокирован в .get(). Это не то же самое, что прерывание потока исполнителя или одной из его задач. Кто-то или что-то прерывает ваш «основной» поток — или, по крайней мере, поток, вызывающий .get().

Прерывания не происходят случайно — какой-то код должен намеренно вызывать прерывание. Прерывание может быть только инициировано вызовом Thread.interrupt(), но есть несколько стандартных утилит Java, которые вызывают это за кулисами, например Future.cancel(true) и ExecutorService.shutdownNow().

Насколько я знаю, нет никакого способа внешнего отслеживания «цепочки причин» или «трассировки стека» причины прерывания. Вы должны обратиться к исходному коду, чтобы определить, где могут быть инициированы прерывания, и, таким образом, сделать вывод, какие вызовы методов вызывают прерывание в вашем случае.

person Mike Clark    schedule 24.11.2010
comment
Я прекрасно понимаю, что это происходит не просто так. Прошу прощения, если так вышло... я хотел знать, где это происходит. Путаница действительно возникла, потому что я думал, что кто-то прерывает callable, что неправильно. Прерывание основного потока было чем-то совершенно ожидаемым, поскольку оно принадлежит симулятору... по крайней мере, теперь я знаю, что означает это голое InterruptedException. - person dgrandes; 24.11.2010
comment
@dgrandes: достаточно честно, я думаю, вы полностью понимаете, что сейчас происходит. Удачи вам, многопоточность может быть сложной задачей! :-) - person Mike Clark; 24.11.2010

Причиной Exception является Throwable (вызов метода не является исключением)

Поток будет прерван только в том случае, если вы это сделаете, это не произойдет случайно.

Если вы действительно понятия не имеете, откуда исходит прерывание, и хотите его игнорировать, вы можете сначала очистить его. позвони Thread.interrupted()

person Peter Lawrey    schedule 24.11.2010
comment
Я знаю, что это бросок, я говорил, что вызываемый объект нигде не вызывал исключения. Извините, что так резко выразился. Как бы то ни было, вызов interrupted() позволил получить результат от get! Большое спасибо. - person dgrandes; 24.11.2010

Это указывает на то, что поток, выполняющий отправленный Callable, прерывается. Это может быть законное прерывание (например, если Callable выполняет какую-то блокирующую операцию, такую ​​как Thread.sleep, и прерывается явным образом через Thread.interrupt()), или может быть так, что ExecutorService (при условии, что вы используете это) отключается через звонок shutDownNow().

Не могли бы вы опубликовать код, используемый для создания пула потоков, вместе с реализацией Callable?

person Adamski    schedule 24.11.2010
comment
На самом деле это именно то, что я думал, что это прерывание будет принадлежать представленному Callable, но это не так. Код метода вызова в callable буквально является println. Служба-исполнитель довольно прямолинейна... - person dgrandes; 24.11.2010
comment
Случайно нажал Enter, извините, служба довольно прямолинейная private ExecutorService pool = Executors.newCachedThreadPool(); Как уже было сказано, проблема заключалась в том, что currentThread, отправляющий вызываемые объекты, был прерван. При внимательном прочтении документации указывается InterruptedException - если текущий поток был прерван во время ожидания. Что имеет смысл в том, что произошло, потому что текущий поток был в прерванном состоянии перед запуском, и именно этот поток ожидает ответа, а не вызываемый поток с суббитами... Я думаю. - person dgrandes; 24.11.2010