在Future Task中,当一个条件满足条件时,终止运行的其他Future任务

时间:2017-09-29 14:29:18

标签: java multithreading future

使用java 8

我正在尝试编写一个prog来从diff服务器下载日志文件,并在这些日志文件中搜索给定的文本。我正在做同步现在。我想并行执行它并发现它可以使用Java中的Future来完成。我正在使用apache.commons.io从URL下载文件。 这是代码片段:

ExecutorService executorService = Executors.newCachedThreadPool();
    List<Future<XCluster>> clusterFutures = new ArrayList<>();
    for(XCluster cluster: clusters) {
        clusterFutures.add(executorService.submit(() ->  {
            return downloadAndSearch(textToSearch, cluster);
        }));
    }
    //For now I'm not doing anything with returned value from Future

但是现在我想终止在Future下启动的其他下载搜索操作,因为预期只能在其中一个服务器中找到给定的搜索。所以没有必要继续我开始的其他Future任务。任何人都可以建议这样做的方法吗?我正在使用java 8,也欢迎其他选项。在此先感谢!

2 个答案:

答案 0 :(得分:1)

ExecutorService有一个shutdownNow方法,它将停止所有线程并关闭服务。

修改

我用shutDownNow进行了一些实验,因为我认为它不能像我想的那样停止线程。 AFAIK它使用中断()但并非所有线程都对中断做出反应。

所以我能提出最好的选择:

首先,创建一个指标类:

public static class Indicator{

    private boolean isReady = false;

    public void ready(){
        isReady = true;
    }

    public boolean isReady(){
        return isReady;
    }
}

您启动的线程应共享一个Indicator实例进行通信。 所以你可以像这样创建一个Callable:

public static class Processor implements Callable<Integer> {

    private volatile Indicator indicator;

    private Integer number;

    public Processor(Integer integer, Indicator isReady){
        this.number = integer;
        this.indicator = isReady;
    }

    @Override
    public Integer call() throws Exception {
        System.out.println("Thread started:" + Thread.currentThread().getId());
        int counter = 0;
        while (!indicator.isReady &&counter < number) {
           // Make complicated things
            Math.sin(counter);
            counter++;
        }
        if(indicator.isReady){
            //another thread finished
            //delete resources
            System.out.println("Thread interrupted: "  + Thread.currentThread().getId() + " " + counter);
            return -1;
        } else {
            System.out.println("Thread finished: "  + Thread.currentThread().getId() + " " + counter);
            indicator.ready();
            return counter;
        }
    }
}

这样,当第一个线程准备就绪时,它可以阻止其他线程,并且它们会在自己清理后进行清理。

我尝试了如下:

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newCachedThreadPool();
    List<Future<Integer>> clusterFutures = new ArrayList<>();
    Indicator indicator = new Indicator();
    clusterFutures.add(executorService.submit(new Processor(100, indicator)));
    clusterFutures.add(executorService.submit(new Processor(10000, indicator)));
    clusterFutures.add(executorService.submit(new Processor(10000000,indicator)));
}

示例输出:

Thread started:11
Thread started:12
Thread finished: 11 100
Thread interrupted: 12 1001
Thread started:13
Thread interrupted: 13 0

旁注:引用的类不必是静态内部类,只是在一个文件中进行实验更容易。

答案 1 :(得分:0)

就代码而言,最简单的解决方案是使用一个取消所有期货的关闭线程:

    final ExecutorService executorService = Executors.newCachedThreadPool();
    final ExecutorService shutdownService = Executors.newSingleThreadExecutor();
    List<Future<XCluster>> clusterFutures = new ArrayList<>();
    for(XCluster cluster: clusters) {
        clusterFutures.add(executorService.submit(() ->  {
            boolean cancelOthers = false;
            try {
                XCluster result = downloadAndSearch(textToSearch, cluster);
                cancelOthers = yourPredicateOfSuccess();
                return result;
            } finally {
              if (cancelOthers) {
                shutdownService.execute(() -> {
                    executorService.shutdownNow();
                });
              }
            }
        }));
    }

另一个线程和try-finally非常重要,因为这可以确保您不会取消几乎成功的方法运行。