2016-09-17 78 views
3

我的要求是在kickstarting從屬作業之前等待兩個線程完成執行。有沒有比使用CountDownLatch等待兩個線程完成任務的更好方法?

爲了做到這一點,我可以創造一個CountDownLatchWaiterThread將等待CountDownLatch變爲零。一個約束是我不能使用主線程等待兩個線程完成。主線程繼續執行其他任務。

這個東西確實有效。不過,我覺得這個解決方案比一個堅實的設計。

我的問題有以下幾點:

  1. 什麼是當前的做法明顯的缺陷?例如虛假信號
  2. 您會推薦什麼設計?

我當前的代碼:

class Waiter implements Runnable { 
    private CountDownLatch latch; 

    Waiter (CountDownLatch latch){ 
     this.latch = latch; 
    } 

    @Override 
    public void run() { 
     System.out.println("Waiter Started running..." + latch.getCount()); 

     try { 
      latch.await(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     System.out.println("Waiter ready to trigger Next Job!"); 
    } 
} 

class Processor implements Runnable { 
    private CountDownLatch latch; 

    Processor (CountDownLatch latch){ 
     this.latch = latch; 
    } 

    @Override 
    public void run() { 
     try { 
      Thread.sleep(300); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     latch.countDown(); 
    } 
} 

public class CountDownLatchDemo { 
    public static void main (String[] args) throws InterruptedException{ 
     CountDownLatch latch = new CountDownLatch(2); 

     ExecutorService executor = Executors.newFixedThreadPool(2); 
     for (int i=0; i< 2; i++){ 
      executor.submit(new Processor(latch)); 
     } 

     ExecutorService waitExecutor = Executors.newFixedThreadPool(2); 
     waitExecutor.submit(new Waiter(latch)); 

     Thread.sleep(3000); 
     executor.shutdown(); 
     waitExecutor.shutdown(); 
     System.out.println("Keep doing other things! Sleep here is just for help you run this code for test!"); 
    } 
} 
+0

這對我來說很好。較低級別的替代方法是在兩個線程上調用join()。 –

+0

加入將需要在我想避免的主線程中,因爲我將需要線程繼續做其他的東西。 – Learner

+1

使用CountDownLatch在這種情況下是一個完全有效的方法,不需要使它更復雜 –

回答

1

CountDownLatch是你的任務妥善解決。但Java 8提供了另一種選擇– CompletableFuture。您可以爲您的任務創建兩個此類期貨,然後使用等待期貨完成的方法之一併異步執行其他方法。例如:

// Submit Task 1 
CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> { 
    try { 
     Thread.sleep(2000); 
    } catch (InterruptedException e) { 
    } 
    System.out.println("Task 1 completed"); 
    return 5; 
}); 
// Submit Task 2 
CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> { 
    try { 
     Thread.sleep(3000); 
    } catch (InterruptedException e) { 
    } 
    System.out.println("Task 2 completed"); 
    return 7; 
}); 
// This call will create a future that will wait for f1 and f2 to complete 
// and then execute the runnable 
CompletableFuture.allOf(f1, f2).thenRun(() -> { 
    System.out.println("Both completed"); 
}); 

所有這些調用都將被異步處理,您的主線程將繼續運行。如果你需要在你的第三個任務的前兩個任務的結果,你可以使用thenAcceptBothAsync()代替allOf()

f1.thenAcceptBothAsync(f2, (a, b) -> System.out.println("Result = " + (a + b))); 

海有很多在CompletableFuture,讓您創建的異步執行的任務鏈的方法。 JVM使用默認的ForkJoinPool來執行它們,但是您可以提供自己的Executor來完成您的未來,並使用它們做許多其他有用的事情。

+0

謝謝。這看起來更乾淨。 – Learner