Java-期货未取消

时间:2018-07-12 11:13:09

标签: java future executorservice cancellation futuretask

我的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()大于20,则该线程计数slider.getValue() ^ 2毫秒。这些Task被提交到ExecutorService

现在,如果Slider改变了它的值,而不同的Task已经开始计数毫秒了,这些Task应该被取消,而新的应该开始计数。

如您所见,代码中有一些打印语句。如果我将Slider剧烈移近50,我放开Slider时会看到类似下面的引用。

  

HighResFutures:1
  LowResFutures:1
  尝试低分辨率取消:false
  尝试高分辨率时取消:true
  中断了!
  低分辨率未来已取消。
  高分辨率未来已取消。
  续!
  低分辨率未来完成。
  续!
  高分辨率未来完成。

但是我看到的是这个

  

HighResFutures:1
  LowResFutures:1
  尝试低分辨率取消:true
  尝试高分辨率时取消:true
  低分辨率未来已取消。
  高分辨率未来已取消。
  续!
  续!
  续!
  续!
  低分辨率未来完成。
  续!
  续!
  续!
  续!
  续!
  续!
  高分辨率未来完成。

因此,首先要注意的是,即使不应该取消正在进行的Future,低分辨率Task的取消也是成功的(这意味着它没有取消该开始了吗?)。其次,我永远也不会“打扰”!印刷。最后,“继续!”在最后一个Task完成之前打印了好几次,这使我相信Task中几乎没有一个被正确取消。你对此有什么看法?我是ExecutorService的新手,不知道发生了什么。非常感谢您的帮助。

0 个答案:

没有答案