Java判斷線程池線程是否執(zhí)行完畢
在使用多線程的時(shí)候有時(shí)候我們會使用 java.util.concurrent.Executors的線程池,當(dāng)多個(gè)線程異步執(zhí)行的時(shí)候,我們往往不好判斷是否線程池中所有的子線程都已經(jīng)執(zhí)行完畢,但有時(shí)候這種判斷卻很有用,例如我有個(gè)方法的功能是往一個(gè)文件異步地寫入內(nèi)容,我需要在所有的子線程寫入完畢后在文件末尾寫“---END---”及關(guān)閉文件流等,這個(gè)時(shí)候我就需要某個(gè)標(biāo)志位可以告訴我是否線程池中所有的子線程都已經(jīng)執(zhí)行完畢,我使用這種方式來判斷。
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("所有的子線程都結(jié)束了!"); break; } Thread.sleep(1000); } final long end = System.currentTimeMillis(); System.out.println((end-start)/1000); } }
當(dāng)調(diào)用ExecutorService.shutdown方法的時(shí)候,線程池不再接收任何新任務(wù),但此時(shí)線程池并不會立刻退出,直到添加到線程池中的任務(wù)都已經(jīng)處理完成,才會退出。在調(diào)用shutdown方法后我們可以在一個(gè)死循環(huán)里面用isTerminated方法判斷是否線程池中的所有線程已經(jīng)執(zhí)行完畢,如果子線程都結(jié)束了,我們就可以做關(guān)閉流等后續(xù)操作了。
判斷線程池中的線程是否全部執(zhí)行完畢的另外一種解決方案則是使用閉鎖(CountDownLatch)來實(shí)現(xiàn),CountDownLatch是一種靈活的閉鎖實(shí)現(xiàn),它可以使一個(gè)或多個(gè)線程等待一組事件發(fā)生。閉鎖狀態(tài)包括一個(gè)計(jì)數(shù)器,該計(jì)數(shù)器被初始化為一個(gè)正數(shù),表示需要等待的事件數(shù)量。countDown方法遞減計(jì)數(shù)器,表示有一個(gè)事件已經(jīng)發(fā)生了,而await方法等待計(jì)數(shù)器達(dá)到零,即表示需要等待的事情都已經(jīng)發(fā)生??梢允褂瞄]鎖來這樣設(shè)計(jì)程序達(dá)到目的:
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(); } }
這種解決方案雖然可以達(dá)到目的但是性能差到?jīng)]朋友,我更傾向于使用第一種方案。
現(xiàn)在我們有了更優(yōu)雅的第三種方案,它的執(zhí)行性能也不錯(cuò)。
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); } }
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java中的相除(/)和取余(%)的實(shí)現(xiàn)方法
這篇文章主要介紹了Java中的相除(/)和取余(%)的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07mybatisplus如何解決分頁最多500條數(shù)據(jù)
這篇文章主要介紹了mybatisplus如何解決分頁最多500條數(shù)據(jù)的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07mybatis-plus?查詢傳入?yún)?shù)Map,返回List<Map>方式
這篇文章主要介紹了mybatis-plus?查詢傳入?yún)?shù)Map,返回List<Map>方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12SpringBoot中注冊Bean的10種方式總結(jié)
在Spring Boot應(yīng)用中,Bean是構(gòu)成應(yīng)用的核心組件,Spring容器負(fù)責(zé)管理這些Bean,包括它們的創(chuàng)建、配置、組裝、管理和銷毀,在Spring Boot中,有多種方式可以注冊Bean,本文將詳細(xì)介紹這些不同的注冊方式,并給出相應(yīng)的示例代碼和適用場景,需要的朋友可以參考下2024-08-08通過IEAD+Maven快速搭建SSM項(xiàng)目的過程(Spring + Spring MVC + Mybatis)
這篇文章主要介紹了通過IEAD+Maven快速搭建SSM項(xiàng)目的過程(Spring + Spring MVC + Mybatis),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01Java實(shí)現(xiàn)復(fù)制文件并命名的超簡潔寫法
這篇文章主要介紹了Java實(shí)現(xiàn)復(fù)制文件并命名的超簡潔寫法,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11Mybatis和orcale update語句中接收參數(shù)為對象的實(shí)例代碼
Mybatis的 mapper.xml 中 update 語句使用 if 標(biāo)簽判斷對像屬性是否為空值。本文重點(diǎn)給大家介紹Mybatis和orcale update語句中接收參數(shù)為對象的實(shí)例代碼,需要的朋友參考下吧2017-09-09SpringBoot整合Redisson的步驟(單機(jī)版)
Redisson非常適用于分布式鎖,而我們的一項(xiàng)業(yè)務(wù)需要考慮分布式鎖這個(gè)應(yīng)用場景,于是我整合它做一個(gè)初步簡單的例子(和整合redis一樣)。2021-05-05