在使用多線程的時候有時候咱們會使用 java.util.concurrent.Executors的線程池,當多個線程異步執行的時候,咱們每每很差判斷是否線程池中全部的子線程都已經執行完畢,但有時候這種判斷卻頗有用,例如我有個方法的功能是往一個文件異步地寫入內容,我須要在全部的子線程寫入完畢後在文件末尾寫「---END---」及關閉文件流等,這個時候我就須要某個標誌位能夠告訴我是否線程池中全部的子線程都已經執行完畢,我使用這種方式來判斷。java
public class MySemaphore { public static void main(String[] args) throws IOException, InterruptedException { final File stream = new File("c:\\temp\\stonefeng\\stream.txt"); final OutputStream os = new FileOutputStream(stream); final OutputStreamWriter writer = new OutputStreamWriter(os); final Semaphore semaphore = new Semaphore(10); ExecutorService exec = Executors.newCachedThreadPool(); final long start = System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { final int num = i; Runnable task = new Runnable() { @Override public void run() { try { semaphore.acquire(); writer.write(String.valueOf(num)+"\n"); semaphore.release(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }; exec.submit(task); } exec.shutdown(); while(true){ if(exec.isTerminated()){ writer.write("---END---\n"); writer.close(); System.out.println("全部的子線程都結束了!"); break; } Thread.sleep(1000); } final long end = System.currentTimeMillis(); System.out.println((end-start)/1000); } }
當調用ExecutorService.shutdown方法的時候,線程池再也不接收任何新任務,但此時線程池並不會馬上退出,直到添加到線程池中的任務都已經處理完成,纔會退出。在調用shutdown方法後咱們能夠在一個死循環裏面用isTerminated方法判斷是否線程池中的全部線程已經執行完畢,若是子線程都結束了,咱們就能夠作關閉流等後續操做了。多線程
判斷線程池中的線程是否所有執行完畢的另一種解決方案則是使用閉鎖(CountDownLatch)來實現,CountDownLatch是一種靈活的閉鎖實現,它能夠使一個或多個線程等待一組事件發生。閉鎖狀態包括一個計數器,該計數器被初始化爲一個正數,表示須要等待的事件數量。countDown方法遞減計數器,表示有一個事件已經發生了,而await方法等待計數器達到零,即表示須要等待的事情都已經發生。能夠使用閉鎖來這樣設計程序達到目的:
異步
1 public class CountDownLatchApproach { 2 public static void main(String[] args) throws IOException, InterruptedException { 3 final int nThreads = 10; 4 final CountDownLatch endGate = new CountDownLatch(nThreads); 5 final File stream = new File("c:\\temp\\stonefeng\\stream.txt"); 6 final OutputStream os = new FileOutputStream(stream); 7 final OutputStreamWriter writer = new OutputStreamWriter(os); 8 ExecutorService exec = Executors.newCachedThreadPool(); 9 for (int i = 0; i < nThreads; i++) { 10 final int num = i; 11 Runnable task = new Runnable() { 12 @Override 13 public void run() { 14 try { 15 writer.write(String.valueOf(num)+"\n"); 16 } catch (IOException e) { 17 e.printStackTrace(); 18 } finally { 19 endGate.countDown(); 20 } 21 } 22 }; 23 exec.submit(task); 24 } 25 endGate.await(); 26 writer.write("---END---\n"); 27 writer.close(); 28 } 29 }
這種解決方案雖然能夠達到目的可是性能差到沒朋友,我更傾向於使用第一種方案。ide
如今咱們有了更優雅的第三種方案,它的執行性能也不錯。post
1 public class MySemaphore { 2 3 public static void main(String[] args) throws IOException, InterruptedException { 4 final File stream = new File("c:\\temp\\stonefeng\\stream.txt"); 5 final OutputStream os = new FileOutputStream(stream); 6 final OutputStreamWriter writer = new OutputStreamWriter(os); 7 final Semaphore semaphore = new Semaphore(10); 8 ExecutorService exec = Executors.newCachedThreadPool(); 9 10 final long start = System.currentTimeMillis(); 11 for (int i = 0; i < 10000000; i++) { 12 final int num = i; 13 Runnable task = new Runnable() { 14 @Override 15 public void run() { 16 try { 17 semaphore.acquire(); 18 writer.write(String.valueOf(num)+"\n"); 19 semaphore.release(); 20 } catch (IOException e) { 21 e.printStackTrace(); 22 } catch (InterruptedException e) { 23 e.printStackTrace(); 24 } 25 } 26 }; 27 exec.submit(task); 28 } 29 exec.shutdown(); 30 exec.awaitTermination(1, TimeUnit.HOURS); 31 writer.write("---END---\n"); 32 writer.close(); 33 System.out.println("ËùÓеÄ×ÓÏ̶߳¼½áÊøÁË£¡"); 34 final long end = System.currentTimeMillis(); 35 System.out.println((end-start)/1000); 36 } 37 }