Подтвердить что ты не робот

Утилита Future.cancel(логический) метод

Я просто изучал пакет java.util.concurrent.

Я узнал, что класс Будущее имеет метод boolean cancel (boolean 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;
}

}

Внутри я предположил, что отмена задачи также остановит выполнение текущего потока (часть "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, было сказано, что

  • Метод "cancel" может только остановить "нераспределенные" задания (что противоречит описанию метода api)
  • Метод отмены просто прерывает текущий поток, который затем должен вернуться из метода run()

Следовательно, я включил часть "OUCH" - цикл while для прерывания, выход был следующим:

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

ВОПРОС:

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

4b9b3361

Ответ 1

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

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

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


Поэтому, вернув это к вашему вопросу, полезность Future.cancel заключается в том, что он решает подмножество проблемы, которая может быть решена в контексте фьючерсов.

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

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

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

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