標籤:

CountDownLatch

2016年面試某公司,一上來讓我先寫段代碼。題目是一個長度是N的整型數組,開啟N個線程讓數組每個元素加上一個隨機數,然後再求出這個數組的所有元素之和。

這道題考察線程之間的同步,主線程等待其他線程完成工作之後,再做自己的工作,可用CountDownLatch。

A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

final static int[] array = new int[10];static class Worker implements Runnable { private CountDownLatch latch; private int index; public Worker(CountDownLatch latch, int index) { this.latch = latch; this.index = index; } @Override public void run() { array[index] += ThreadLocalRandom.current().nextInt(); latch.countDown(); }}public static void main(String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch(10); for (int i = 0; i < 10; i++) { new Thread(new Worker(latch, i)).start(); } latch.await(); // 等待 int sum = 0; for (int i = 0; i < 10; i++) { sum += array[i]; } System.out.println(sum);}

這段代碼簡潔明了,但還是有需要留心的地方。比如static的使用,static類只能訪問static修飾的變數。再比如,公共訪問的變數沒有必要傳入到每個線程里,用final修飾即可。

我當時用的是以下方法來判斷,這是不準確的

public static int activeCount() { return currentThread().getThreadGroup().activeCount();}

還可以使用java.lang.Thread#join()

List<Thread> threads = new ArrayList<Thread>(N); for (int i = 0; i < N; i++) { Thread thread = new Thread(new Worker(i)); threads.add(thread); thread.start(); } // wait until done for (Thread thread : threads) thread.join(); }

thread.join()不能寫在第一個循環里,否則主線程會在這一行阻塞,每啟動一個線程會等待它結束,再會去啟動下一個線程。

還可以使用線程池

ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { executorService.submit(new Worker(i)); } executorService.shutdown(); // 禁止提交任務,但已提交的會完成 while (!executorService.awaitTermination(1, TimeUnit.SECONDS)) { System.out.println("線程池尚未關閉"); }

awaitTermination方法:接收人timeout和TimeUnit兩個參數,用於設定超時時間及單位。當等待超過設定時間時,會監測ExecutorService是否已經關閉,若關閉則返回true,否則返回false。一般情況下會和shutdown方法組合使用。

最後看一段JDK文檔中的代碼:

class Driver { // ... void main() throws InterruptedException { CountDownLatch startSignal = new CountDownLatch(1); CountDownLatch doneSignal = new CountDownLatch(N); for (int i = 0; i < N; ++i) // create and start threads new Thread(new Worker(startSignal, doneSignal)).start(); doSomethingElse(); // dont let run yet startSignal.countDown(); // let all threads proceed doSomethingElse(); doneSignal.await(); // wait for all to finish } } class Worker implements Runnable { private final CountDownLatch startSignal; private final CountDownLatch doneSignal; Worker(CountDownLatch startSignal, CountDownLatch doneSignal) { this.startSignal = startSignal; this.doneSignal = doneSignal; } public void run() { try { startSignal.await(); doWork(); doneSignal.countDown(); } catch (InterruptedException ex) {} // return; } void doWork() { ... } }

參考資料:CountDownLatch (Java Platform SE 8 )


推薦閱讀:

Mutex and Spinlock
JDK並發類
semaphore
CyclicBarrier

TAG:並發 |