方案(一)CountDownLatch:
使用CountDownLatch+Semaphore方式實現:
import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; public class TestABC { public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch=new CountDownLatch(2); Semaphore semaphoreC = new Semaphore(1); Thread threadA = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(newjava.util.Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); countDownLatch.countDown(); } }, "Thread-A"); Thread threadB = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(newjava.util.Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); countDownLatch.countDown(); } }, "Thread-B"); Thread threadC = new Thread(new Runnable() { @Override public void run() { try { semaphoreC.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); semaphoreC.release(); } }, "Thread-C"); // 占用C鎖,直到A/B線程完成后,才釋放C鎖。 semaphoreC.acquire(); threadA.start(); threadB.start(); threadC.start(); countDownLatch.await(); // 釋放C鎖,讓C線程有獲取鎖的可能 semaphoreC.release(); } }
上邊使用CountDownLatch+Semaphore方式實現,但是缺點:上邊這種方式會導致線程阻塞情況。下邊這種方案是可以實現不阻塞線程的用法:

import java.util.concurrent.CountDownLatch; public class TestABC { public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch=new CountDownLatch(2); Thread threadA = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(new java.util.Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); countDownLatch.countDown(); } }, "Thread-A"); Thread threadB = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(new java.util.Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); countDownLatch.countDown(); } }, "Thread-B"); Thread threadC = new Thread(new Runnable() { @Override public void run() { // 在C中等待A/B運算結束 try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); throw new RuntimeException("CountDownLatch等待失敗。。。",e); } System.out.println(Thread.currentThread().getName()); } }, "Thread-C"); threadA.start(); threadB.start(); threadC.start(); } }
方案(二):CyclicBarrier
import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; public class TestABC { public static void main(String[] args) throws InterruptedException { CyclicBarrier cyclicBarrier=new CyclicBarrier(3); Thread threadA = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(new java.util.Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); // 沖破柵欄代表A線程結束 try { cyclicBarrier.await(); } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); throw new RuntimeException("cylicBarrier.await()拋出異常:",e); } } }, "Thread-A"); Thread threadB = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(new java.util.Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); // 沖破柵欄代表B線程結束 try { cyclicBarrier.await(); } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); throw new RuntimeException("cylicBarrier.await()拋出異常:",e); } } }, "Thread-B"); Thread threadC = new Thread(new Runnable() { @Override public void run() { // 等待前兩個(A/B)線程結束,只有前兩個(A/B)線程結束了才能滿足3個線程都沖破柵欄, try { // 等待柵欄被沖破,沖破柵欄的條件是:A/B/C三個線程都到達await()。 // 只有柵欄沖破,才能向下執行,否則先到達的線程等待。 cyclicBarrier.await(); } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); throw new RuntimeException("cylicBarrier.await()拋出異常:",e); } // 滿足了三個線程都沖破柵欄才向下執行 System.out.println(Thread.currentThread().getName()); } }, "Thread-C"); threadA.start(); threadB.start(); threadC.start(); } }