简体   繁体   English

如何在两个返回布尔值的并行线程上用Java进行短路评估?

[英]How to perform short-circuit evaluation in Java on two parallel threads that return boolean values?

I'm looking for guidance for a problem logically equivalent to the following: 我正在寻找逻辑上等同于以下问题的指导:

public boolean parallelOR() {
    ExecutorService executor = Executors.newFixedThreadPool(2);
    Future<Boolean> taskA = executor.submit( new SlowTaskA() );
    Future<Boolean> taskB = executor.submit( new SlowTaskB() );

    return taskA.get() || taskB.get(); // This is not what I want
    // Exception handling omitted for clarity
 }

The above construction gives the correct result but always waits for taskA to complete even if the result is already known since taskB has completed . 上述结构给出了正确的结果, 但是即使从taskB完成后结果已知,总是等待taskA完成

Is there a better construction which will allow a value to be returned if either of the threads returns true without waiting for the second thread to complete? 有没有更好的结构,如果任何一个线程返回true而不等待第二个线程完成,它将允许返回一个值?

(The platform involved is Android, if that affects the result). (涉及的平台是Android,如果这会影响结果)。

try Using ExecutorCompletionService ... something like 尝试使用ExecutorCompletionService ...类似于

    ExecutorService pool = Executors.newFixedThreadPool(2);
    ExecutorCompletionService<Result> completionService = new ExecutorCompletionService<Result>(pool);
completionService.submit(new SlowTaskA());
completionService.submit(new SlowTaskB());
    Future<Result> future;
            try {
                future = completionService.take();
                Result currentResult=null;
                try {
                    currentResult = future.get();
                } catch (ExecutionException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                // got the 1st result in obj currentResult, return true or obj
                return true;
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }

Here's an implementation of ParallelOr using ExecutorCompletionService . 这是使用ExecutorCompletionService的ParallelOr的实现。 It waits on tasks until one returns true . 它会等待任务,直到返回true If none do, it eventually returns false . 如果没有,它最终返回false

public class ParallelOr {

    static class LongTask implements Callable<Boolean> {

        private int milliseconds;
        private boolean val;

        public LongTask(int milliseconds, boolean val) {
            this.milliseconds = milliseconds;
            this.val = val;
        }

        @Override
        public Boolean call() throws Exception {
            try {
                Thread.sleep(milliseconds);
            } catch(Exception ex) {}
            return val;
        }
    }

    static boolean ParallelOr(List<Callable<Boolean>> tasks) {
        ExecutorService pool = Executors.newFixedThreadPool(tasks.size());
        ExecutorCompletionService<Boolean> completionService
                = new ExecutorCompletionService<Boolean>(pool);

        for(Callable<Boolean> task : tasks) {
            completionService.submit(task);
        }

        for(int i = 0; i < tasks.size(); i++) {
            try {
                Future<Boolean> result = completionService.take();
                if(result.get()) {
                    return true;
                }
            } catch (InterruptedException e) {
            } catch (ExecutionException e) {}
        }

        return false;
    }


    public static void main(String[] args) {
        ArrayList<Callable<Boolean>> tasks = new ArrayList<Callable<Boolean>>();

        tasks.add(new LongTask(1000, true));
        tasks.add(new LongTask(500, false));
        tasks.add(new LongTask(6000, false));

        boolean result = ParallelOr(tasks);

        System.out.println(result);
    }
}

Thanks to @Lav for pointing out the ExecutorCompleteionService class. 感谢@Lav指出了ExecutorCompleteionService类。

I think monitor logic might work nicely in this case, though it is dependent upon you being able to add alter the callables to receive a reference. 我认为监视器逻辑在这种情况下可能会很好地工作,但它取决于您是否能够添加更改callables来接收引用。 It could look like this in the parallelOR() method: 它可能在parallelOR()方法中看起来像这样:

ExecutorService executor = Executors.newFixedThreadPool(2);
    final Object monitor = new Object();
    Future<Boolean> taskA = executor.submit( new SlowTaskA(monitor) );
    Future<Boolean> taskB = executor.submit( new SlowTaskB(monitor) );
    Boolean ret = null,;
    try {
        loop:while(true){
            synchronized(monitor){
                monitor.wait();
            }
            if(taskA.isDone()){
                ret = taskA.get();
                if(ret.booleanValue()){
                    taskB.cancel(true); // If you can.
                    break loop;
                }
            }
            if(taskB.isDone()){
                ret = taskB.get();
                if(ret.booleanValue()){
                    taskA.cancel(true);
                    break loop;
                }
            }
            // Ifs in case of spurious wake-up
        }           
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }

While at the end of the call() method in your callables you would have: 在您的callables中call()方法结束时,您将拥有:

synchronized(monitor){
            monitor.notify();
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM