6

Tôi đang tìm hướng dẫn cho một vấn đề một cách logic tương đương như sau:Làm thế nào để thực hiện đánh giá ngắn mạch trong Java trên hai luồng song song trả về giá trị boolean?

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 
} 

Việc xây dựng ở trên cho kết quả chính xác nhưng luôn luôn chờ đợi để hoàn thành taskA ngay cả khi kết quả đã được biết đến từ taskB có hoàn thành.

Có cấu trúc nào tốt hơn sẽ cho phép giá trị trả về nếu một trong hai chủ đề trả về true mà không cần đợi chuỗi thứ hai hoàn thành?

(Nền tảng liên quan là Android, nếu điều đó ảnh hưởng đến kết quả).

+0

Bạn có thể sửa đổi các nhiệm vụ? – Collin

+0

Vì vậy, bạn không muốn chờ đợi cho các chủ đề A và B để hoàn thành trước khi nhận được valus ??? và bạn muốn nó khi A được thực hiện bạn sẽ nhận được giá trị và ngược lại? –

+0

Ý tưởng có vẻ là nếu taskB kết thúc trước, và là đúng, thì bạn có thể đoản mạch và không đợi taskA kết thúc. – Collin

Trả lời

2

Dưới đây là một thực hiện ParallelOr sử dụng ExecutorCompletionService. Nó đợi nhiệm vụ cho đến khi một trả về true. Nếu không có, nó cuối cùng trả về 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); 
    } 
} 

Nhờ @Lav để chỉ ra lớp ExecutorCompleteionService.

3

thử dùng ExecutorCompletionService ... cái gì đó như

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(); 
      } 
+0

+1 - Tuyệt! Tôi chưa từng gặp 'ExecutorCompletionService' trước đây. –

1

Tôi nghĩ rằng logic theo dõi có thể hoạt động tốt trong trường hợp này, mặc dù nó phụ thuộc vào việc bạn có thể thêm thay đổi các callables để nhận tham chiếu. Nó có thể trông như thế này trong phương pháp 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(); 
    } 

Trong khi ở phần cuối của phương pháp gọi() trong callables của bạn, bạn sẽ có:

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

Có thể điều này là cố hữu trong cách nó được thiết lập, nhưng làm thế nào bạn sẽ đảm bảo 'isDone()' sẽ trả về 'true' nếu bạn đang báo hiệu từ bên trong nhiệm vụ? – Collin

+0

Tôi không chắc chắn ý bạn là gì ở đây. Tôi sẽ đặt khối này ở phần cuối của phương thức call() của bạn để bạn có thể gọi một cách rõ ràng đã xử lý xong. – SeanTheStudent

Các vấn đề liên quan