2012-03-02 4 views
29

Я просто изучал пакет java.util.concurrent.Утилита Future.cancel (boolean) method

я узнал, что класс «Future» имеет метод булево отменить (булево mayInterruptIfRunning)

Пожалуйста прилагается тестовый код, который я написал:

package com.java.util.concurrent; 

import java.util.concurrent.Callable; 
import java.util.concurrent.FutureTask; 
import java.util.concurrent.ScheduledFuture; 
import java.util.concurrent.ScheduledThreadPoolExecutor; 

public class FutureTester { 

/** 
* @param args 
* @throws InterruptedException 
*/ 
public static void main(String[] args) throws InterruptedException { 
    // TODO Auto-generated method stub 
    int poolCnt = 1; 
    Callable<NumberPrinter> numberPrinter = null; 
    ScheduledThreadPoolExecutor schPool = new ScheduledThreadPoolExecutor(
      poolCnt); 
    ScheduledFuture<NumberPrinter>[] numPrinterFutures = new ScheduledFuture[poolCnt]; 
    FutureTask<NumberPrinter>[] futureTask = new FutureTask[poolCnt]; 

    for (int i = 0; i < poolCnt; i++) { 
     numberPrinter = new NumberPrinter(); 
     futureTask[i] = new FutureTask<NumberPrinter>(numberPrinter); 

     /* 
     * numPrinterFutures[i] = (ScheduledFuture<NumberPrinter>) schPool 
     * .schedule(futureTask[i], 0, TimeUnit.MILLISECONDS); 
     */ 
     numPrinterFutures[i] = (ScheduledFuture<NumberPrinter>) schPool 
       .submit(futureTask[i]); 
    } 

    //Thread.sleep(30); 

    if (numPrinterFutures.length > 0) { 

     System.out.println("Task completed ? " 
       + numPrinterFutures[0].isDone()); 

     System.out.println("Task cancelled ? " 
       + numPrinterFutures[0].cancel(true)); 

     System.out.println("Is task cancelled ? " 
       + numPrinterFutures[0].isCancelled()); 
    } 
} 

} 

class NumberPrinter implements Callable<NumberPrinter> { 

private int counter = 10; 

@Override 
public NumberPrinter call() throws Exception { 
    // TODO Auto-generated method stub 

    while (counter > 0) { 
     if (Thread.interrupted()) {/*OUCH !!!*/ 
      return null; 
     } 
     System.out.println("counter = " + (counter--)); 
    } 

    return this; 
} 

} 

Intially, я предположил, что отмена задачи также остановит выполнение бегущей нити (часть «OUCH» НЕ включена). Но я получил выход следующим образом:

counter = 10 
Task completed ? false 
counter = 9 
Task cancelled ? true 
counter = 8 
Is task cancelled ? true 
counter = 7 
counter = 6 
counter = 5 
counter = 4 
counter = 3 
counter = 2 
counter = 1 

При дальнейшем чтении самого StackOverflow, было сказано, что

  1. «Отменить» метод может только остановить «Не начато» рабочих мест (что противоречит описанию апи метода)
  2. метод отмены просто прерывает текущую нить, которая затем должен вернуться из метода Run()

Таким образом, я включил «АЙ» часть - проверка петли во время прерывания, выход следующим образом:

Task completed ? false 
counter = 10 
Task cancelled ? true 
Is task cancelled ? true 

ВОПРОС:

Если один должен написать что-то аналогичное к части «OUCH», чтобы остановить выполняемый поток, какова утилита/значение метода отмены. Как обертывание Callable в FutureTask помогает, если Thread нельзя остановить, отменив? Какая проектная/концептуальная/логическая часть, которую я пропускаю?

+1

Я столкнулся с той же проблемой. Я не знал, почему мои пулы потоков истощаются в определенный момент. Теперь я понял, почему. Благодарю. – tejas

ответ

19

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

В самом деле, если вы посмотрите на API Thread, вы заметите, что есть некоторые методы, называемые destroy, pause, stop и resume, которые были устаревшими в Java 1.1. Причина, по которой они устарели, заключается в том, что разработчики Java поняли, что их вообще нельзя использовать безопасно. Причины объясняются в примечании "Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?".

Проблема связана с моделью потоков Java, и ее можно избежать только путем ограничения способности одного потока взаимодействовать с объектами, используемыми другими потоками. Существует JSR, который указывает один из способов сделать это ... Изолирует ... но никакие обычные JVM не реализуют эти API, насколько мне известно.


Так чего это обратно на свой вопрос, полезность Future.cancel является то, что он решает подмножество проблемы, может быть решена в контексте будущего.

7

Вызов cancel(true) предотвратит выполнение Будущим, если он еще не запущен, и будет interrupted в случае его запуска. На данный момент на разработчика налагается бремя отмены Future.

Поскольку это пул потоков, не имеет смысла останавливать поток (хотя редко бывает когда-либо иметь смысл остановить поток). Отмена/прерывание не приведет к выходу потока из метода запуска. После выполнения метода вызова Callable он просто вытащит следующий элемент из рабочей очереди и обработает его.

Утилита метода cancel - просто сигнализировать исполняющему потоку, что какой-то процесс хочет, чтобы Callable останавливался, а не поток, поэтому вам придется обрабатывать остановку Callable самостоятельно.

0

Предположим, что код, который работает как часть вашего будущего, не поддерживает совместную отмену или прерывание. Тогда отмена невыбранной задачи - лучшее, что вы можете сделать. Вот почему этот метод существует.

В целом, я думаю об отмене как строго кооперативном. Просто отмена какой-либо части кода силой может привести к поврежденному состоянию.

24

Как обертывание Callable в FutureTask помогает, если Thread нельзя остановить путем отмены?

Вы хотите отменить задачу, а не поток, выполняющий ее. Использование cancel (true) предотвращает запуск задачи (но не удаляет ее из очереди) и прерывает поток, если задача запущена. Задача может игнорировать прерывание, но нет чистого способа убить поток, не убивая весь процесс.

-2

В вашем коде есть ошибка. Вы должны проверить, является ли прервано или не используя текущий поток,

if(Thread.currentThread().isInterrupted()) { /*OUCH !!!*/ 
    return null; 
} 

Таким образом, выполнение потока прерывается и возвращается из метода выполнения.

+0

Зачем использовать 'Thread.currentThread(). IsInterrupted()' вместо 'Thread.interrupted()'? – Roman

+0

@Roman __Thread.currentThread(). IsInterrupted() __ не очищает прерванный статус, но позже очищает его. –

+0

Непонятно вопрос. Удалит сообщение. –