2014-01-23 2 views
4

Я только что заметил следующие явления при отмене Будущего, возвращенного ForkJoinPool. С учетом следующего примера кода:ForkJoinPool сбрасывает поток прерывистое состояние

ForkJoinPool pool = new ForkJoinPool(); 
Future<?> fut = pool.submit(new Callable<Void>() { 

    @Override 
    public Void call() throws Exception { 
    while (true) { 
     if (Thread.currentThread().isInterrupted()) { // <-- never true 
     System.out.println("interrupted"); 
     throw new InterruptedException(); 
     } 
    } 
    } 
}); 

Thread.sleep(1000); 
System.out.println("cancel"); 
fut.cancel(true); 

Программа никогда не печатает interrupted. Документы из ForkJoinTask#cancel(boolean) говорят:

mayInterruptIfRunning - это значение не имеет никакого эффекта в реализации по умолчанию, потому что прерывания не используется для управления отменой.

Если ForkJoinTasks игнорирует прерывания, как еще вы должны проверять отмену внутри Callables, отправленных в ForkJoinPool?

+0

BTW, почему вы используете FJP для этого случая? – Mikhail

+0

@ Михайл это всего лишь очень маленький пример нашего прецедента. Мы запускаем некоторые RecursiveActions внутри вызываемого, которые вызываются на ForkJoinTask.getPool() – Korbi

ответ

5

Это происходит потому, что Future<?> является ForkJoinTask.AdaptedCallable, который проходит ForkJoinTask, чей отменить метод:

public boolean cancel(boolean mayInterruptIfRunning) { 
    return setCompletion(CANCELLED) == CANCELLED; 
} 

private int setCompletion(int completion) { 
    for (int s;;) { 
     if ((s = status) < 0) 
      return s; 
     if (UNSAFE.compareAndSwapInt(this, statusOffset, s, completion)) { 
      if (s != 0) 
       synchronized (this) { notifyAll(); } 
      return completion; 
     } 
    } 
} 

Она не делает каких-либо перерывов, он просто устанавливает статус. Я полагаю, что это происходит, потому что ForkJoinPools's Future s может иметь очень сложную древовидную структуру, и неясно, в каком порядке их отменить.

+0

Спасибо Михаилу за ваше расследование. Похоже, нет возможности проверить отмену в пределах вызываемого. Мне нужно отправить ForkJoinTask и вызвать isCancelled() на этом, что отстойно, потому что вам всегда нужно передать ссылку на ForkJoinTask, чтобы проверить отмену – Korbi

Смежные вопросы