Ява - фьючерсы не отменяются

У меня была проблема с моим фьючерсным контрактом, возвращенным из моего ExecutorService, который не отменялся должным образом в течение некоторого времени. Я написал MCVE, который, я считаю, отражает корень моих проблем.

Вот код:

public class MainTest extends Application {

private ExecutorService threadPool = Executors.newFixedThreadPool(8);
private int lowResolution = 20;
private List<Future<Object>> lowResFutureList = 
        Collections.synchronizedList(new  ArrayList<Future<Object>>());
private List<Future<Object>> highResFutureList = 
        Collections.synchronizedList(new  ArrayList<Future<Object>>());

private Slider slider = new Slider();

    @Override
    public void start(Stage primaryStage) {
        slider.valueProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                updateLowResImage();
            }
        });
        slider.showTickLabelsProperty().set(true);
        slider.showTickMarksProperty().set(true);
        slider.setMax(60);

        Scene scene = new Scene(slider);

        primaryStage.setTitle("Test");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

    public void updateLowResImage() {
        System.out.println("HighResFutures: " + highResFutureList.size() + "\n"
                + "LowResFutures: " + lowResFutureList.size());
        for(Future<Object> future : lowResFutureList) {
            if(future != null) {
                System.out.println("Attempting low res cancel: " + future.cancel(false));   
            }
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                Future<Object> future = threadPool.submit(new ImageTask(lowResolution, lowResolution));
                lowResFutureList.add(future);
                try {
                    future.get();
                    System.out.println("Low res Future completed.");
                } catch (Exception e) {
                    System.out.println("Low resolution Future cancelled.");
                } finally {
                    lowResFutureList.remove(future);
                }
            }
        }).start();

        int resolution = (int) slider.getValue();
        if(resolution > lowResolution) {
            updateHighResImage(resolution);
        }
    }

    public synchronized void updateHighResImage(int resolution) {
        for(Future<Object> future : highResFutureList) {
            if(future != null) {
                System.out.println("Attempting high res cancel: " + future.cancel(true));   
            }
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
            Future<Object> future = threadPool.submit(new ImageTask(resolution, resolution));
                highResFutureList.add(future);
                try {
                    future.get();
                    System.out.println("High res Future completed.");
                } catch (Exception e) {
                    System.out.println("High resolution Future cancelled.");
                } finally {
                    highResFutureList.remove(future);
                }
            }
        }).start();
    }

    private class ImageTask implements Callable<Object> {

        int width = 0;
        int height = 0;

        private ImageTask(int width, int height) {
            this.width = width;
            this.height = height;
        }

        @Override
        public Object call() throws Exception {
            for(int x = 0; x < width; x++) {
                for(int y = 0; y < height; y++) {
                    if(Thread.interrupted()) {
                        System.out.println("Interrupted!");
                        return null;
                    }
                    try {
                        Thread.sleep(1);
                    } catch(Exception e) {
                        System.out.print("Cancelled! ");
                    }
                }
            }
            System.out.println("Continued!");
            return null;
        }
    }
}

Я считаю, что некоторые объяснения необходимы. Таким образом, код поднимает Slider с диапазоном от 0 до 60. Каждый раз, когда ползунок меняет свое значение, он должен создавать Task это составляет 20^2 миллисекунд. Когда это сделано, он запускает другой поток, который считает slider.getValue()^ 2 миллисекунды, если slider.getValue() больше 20. Эти Tasks представлены на ExecutorService,

Теперь, если Slider меняет свое значение в то время как разные Taskони уже считают миллисекунды эти Tasks должны быть отменены, а новые должны начать отсчет.

Как видите, в коде есть несколько операторов печати. Если я перееду Slider энергично близко к 50, я ожидаю увидеть что-то вроде цитаты ниже, когда я отпущу Slider,

HighResFutures: 1
LowResFutures: 1
Попытка отмены низкого разрешения: ложь
Попытка отмены высокого разрешения: true
Прерванный!
Низкое разрешение Будущее отменено.
Высокое разрешение Будущее отменено.
Продолжение!
Низкое разрешение Будущее завершено.
Продолжение!
Высокое разрешение Будущее завершено.

Но то, что я вижу, это:

HighResFutures: 1
LowResFutures: 1
Попытка отмены низкого разрешения: правда
Попытка отмены высокого разрешения: true
Низкое разрешение Будущее отменено.
Высокое разрешение Будущее отменено.
Продолжение!
Продолжение!
Продолжение!
Продолжение!
Низкое разрешение Будущее завершено.
Продолжение!
Продолжение!
Продолжение!
Продолжение!
Продолжение!
Продолжение!
Высокое разрешение Будущее завершено.

Итак, первое, что нужно отметить, это то, что отмена низкого разрешения FutureS успешно, хотя он не должен быть в состоянии отменить текущий Tasks (это значит, что у него не было времени начать?). Во-вторых, я никогда не получаю "Прервано!" распечатаны. И, наконец, "Продолжение!" печатается несколько раз до завершения финала Task что заставляет меня верить, что почти никто из Tasks отменены должным образом. Что вы думаете об этом? Я очень новичок в ExecutorService и понятия не имею, что происходит. Буду признателен за любую оказанную помощь.

0 ответов

Другие вопросы по тегам