1. 程式人生 > 程式設計 >Java判斷執行緒池執行緒是否執行完畢

Java判斷執行緒池執行緒是否執行完畢

在使用多執行緒的時候有時候我們會使用 java.util.concurrent.Executors的執行緒池,當多個執行緒非同步執行的時候,我們往往不好判斷是否執行緒池中所有的子執行緒都已經執行完畢,但有時候這種判斷卻很有用,例如我有個方法的功能是往一個檔案非同步地寫入內容,我需要在所有的子執行緒寫入完畢後在檔案末尾寫“---END---”及關閉檔案流等,這個時候我就需要某個標誌位可以告訴我是否執行緒池中所有的子執行緒都已經執行完畢,我使用這種方式來判斷。

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方法等待計數器達到零,即表示需要等待的事情都已經發生。可以使用閉鎖來這樣設計程式達到目的:

public class CountDownLatchApproach {
  public static void main(String[] args) throws IOException,InterruptedException {
    final int nThreads = 10;
    final CountDownLatch endGate = new CountDownLatch(nThreads);
    final File stream = new File("c:\\temp\\stonefeng\\stream.txt");
    final OutputStream os = new FileOutputStream(stream);
    final OutputStreamWriter writer = new OutputStreamWriter(os);
    ExecutorService exec = Executors.newCachedThreadPool();
    for (int i = 0; i < nThreads; i++) {
      final int num = i;
      Runnable task = new Runnable() {
        @Override
        public void run() {
          try {
            writer.write(String.valueOf(num)+"\n");
          } catch (IOException e) {
            e.printStackTrace();
          } finally {
            endGate.countDown();
          }
        }
      };
      exec.submit(task);
    }
    endGate.await();
    writer.write("---END---\n");
    writer.close();
  }
}

這種解決方案雖然可以達到目的但是效能差到沒朋友,我更傾向於使用第一種方案。

現在我們有了更優雅的第三種方案,它的執行效能也不錯。

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();
    exec.awaitTermination(1,TimeUnit.HOURS);
    writer.write("---END---\n");
    writer.close();
    System.out.println("ËùÓеÄ×ÓÏ̶߳¼½áÊøÁË£¡");
    final long end = System.currentTimeMillis();
    System.out.println((end-start)/1000);
  }
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。