真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

線程池的創(chuàng)建方式有哪些

這篇文章主要講解了“線程池的創(chuàng)建方式有哪些”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“線程池的創(chuàng)建方式有哪些”吧!

壽寧網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián)公司,壽寧網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為壽寧1000+提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站制作要多少錢,請找那個售后服務(wù)好的壽寧做網(wǎng)站的公司定做!

什么是線程池?

線程池(ThreadPool)是一種基于池化思想管理和使用線程的機(jī)制。它是將多個線程預(yù)先存儲在一個“池子”內(nèi),當(dāng)有任務(wù)出現(xiàn)時可以避免重新創(chuàng)建和銷毀線程所帶來性能開銷,只需要從“池子”內(nèi)取出相應(yīng)的線程執(zhí)行對應(yīng)的任務(wù)即可。

池化思想在計(jì)算機(jī)的應(yīng)用也比較廣泛,比如以下這些:

  • 內(nèi)存池(Memory Pooling):預(yù)先申請內(nèi)存,提升申請內(nèi)存速度,減少內(nèi)存碎片。

  • 連接池(Connection Pooling):預(yù)先申請數(shù)據(jù)庫連接,提升申請連接的速度,降低系統(tǒng)的開銷。

  • 實(shí)例池(Object Pooling):循環(huán)使用對象,減少資源在初始化和釋放時的昂貴損耗。

線程池的優(yōu)勢主要體現(xiàn)在以下 4 點(diǎn):

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 降低資源消耗:通過池化技術(shù)重復(fù)利用已創(chuàng)建的線程,降低線程創(chuàng)建和銷毀造成的損耗。

  3. 提高響應(yīng)速度:任務(wù)到達(dá)時,無需等待線程創(chuàng)建即可立即執(zhí)行。

  4. 提高線程的可管理性:線程是稀缺資源,如果無限制創(chuàng)建,不僅會消耗系統(tǒng)資源,還會因?yàn)榫€程的不合理分布導(dǎo)致資源調(diào)度失衡,降低系統(tǒng)的穩(wěn)定性。使用線程池可以進(jìn)行統(tǒng)一的分配、調(diào)優(yōu)和監(jiān)控。

  5. 提供更多更強(qiáng)大的功能:線程池具備可拓展性,允許開發(fā)人員向其中增加更多的功能。比如延時定時線程池ScheduledThreadPoolExecutor,就允許任務(wù)延期執(zhí)行或定期執(zhí)行。

同時阿里巴巴在其《Java開發(fā)手冊》中也強(qiáng)制規(guī)定:線程資源必須通過線程池提供,不允許在應(yīng)用中自行顯式創(chuàng)建線程。

  • 說明:線程池的好處是減少在創(chuàng)建和銷毀線程上所消耗的時間以及系統(tǒng)資源的開銷,解決資源不足的問題。如果不使用線程池,有可能造成系統(tǒng)創(chuàng)建大量同類線程而導(dǎo)致消耗完內(nèi)存或者“過度切換”的問題。

知道了什么是線程池以及為什要用線程池之后,我們再來看怎么用線程池。

線程池使用

線程池的創(chuàng)建方法總共有 7 種,但總體來說可分為 2 類:

  • 一類是通過 ThreadPoolExecutor 創(chuàng)建的線程池;

  • 另一個類是通過 Executors 創(chuàng)建的線程池。

線程池的創(chuàng)建方式有哪些

線程池的創(chuàng)建方式總共包含以下 7 種(其中 6 種是通過 Executors 創(chuàng)建的,1 種是通過 ThreadPoolExecutor  創(chuàng)建的):

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. Executors.newFixedThreadPool:創(chuàng)建一個固定大小的線程池,可控制并發(fā)的線程數(shù),超出的線程會在隊(duì)列中等待;

  3. Executors.newCachedThreadPool:創(chuàng)建一個可緩存的線程池,若線程數(shù)超過處理所需,緩存一段時間后會回收,若線程數(shù)不夠,則新建線程;

  4. Executors.newSingleThreadExecutor:創(chuàng)建單個線程數(shù)的線程池,它可以保證先進(jìn)先出的執(zhí)行順序;

  5. Executors.newScheduledThreadPool:創(chuàng)建一個可以執(zhí)行延遲任務(wù)的線程池;

  6. Executors.newSingleThreadScheduledExecutor:創(chuàng)建一個單線程的可以執(zhí)行延遲任務(wù)的線程池;

  7. Executors.newWorkStealingPool:創(chuàng)建一個搶占式執(zhí)行的線程池(任務(wù)執(zhí)行順序不確定)【JDK 1.8 添加】。

  8. ThreadPoolExecutor:最原始的創(chuàng)建線程池的方式,它包含了 7 個參數(shù)可供設(shè)置,后面會詳細(xì)講。

單線程池的意義從以上代碼可以看出 newSingleThreadExecutor 和 newSingleThreadScheduledExecutor  創(chuàng)建的都是單線程池,那么單線程池的意義是什么呢?答:雖然是單線程池,但提供了工作隊(duì)列,生命周期管理,工作線程維護(hù)等功能。

那接下來我們來看每種線程池創(chuàng)建的具體使用。

1.FixedThreadPool

創(chuàng)建一個固定大小的線程池,可控制并發(fā)的線程數(shù),超出的線程會在隊(duì)列中等待。

使用示例如下:

public static void fixedThreadPool() {     // 創(chuàng)建 2 個數(shù)據(jù)級的線程池     ExecutorService threadPool = Executors.newFixedThreadPool(2);      // 創(chuàng)建任務(wù)     Runnable runnable = new Runnable() {         @Override         public void run() {             System.out.println("任務(wù)被執(zhí)行,線程:" + Thread.currentThread().getName());         }     };      // 線程池執(zhí)行任務(wù)(一次添加 4 個任務(wù))     // 執(zhí)行任務(wù)的方法有兩種:submit 和 execute     threadPool.submit(runnable);  // 執(zhí)行方式 1:submit     threadPool.execute(runnable); // 執(zhí)行方式 2:execute     threadPool.execute(runnable);     threadPool.execute(runnable); }

執(zhí)行結(jié)果如下:

線程池的創(chuàng)建方式有哪些

如果覺得以上方法比較繁瑣,還用更簡單的使用方法,如下代碼所示:

public static void fixedThreadPool() {     // 創(chuàng)建線程池     ExecutorService threadPool = Executors.newFixedThreadPool(2);     // 執(zhí)行任務(wù)     threadPool.execute(() -> {         System.out.println("任務(wù)被執(zhí)行,線程:" + Thread.currentThread().getName());     }); }

2.CachedThreadPool

創(chuàng)建一個可緩存的線程池,若線程數(shù)超過處理所需,緩存一段時間后會回收,若線程數(shù)不夠,則新建線程。

使用示例如下:

public static void cachedThreadPool() {     // 創(chuàng)建線程池     ExecutorService threadPool = Executors.newCachedThreadPool();     // 執(zhí)行任務(wù)     for (int i = 0; i < 10; i++) {         threadPool.execute(() -> {             System.out.println("任務(wù)被執(zhí)行,線程:" + Thread.currentThread().getName());             try {                 TimeUnit.SECONDS.sleep(1);             } catch (InterruptedException e) {             }         });     } }

執(zhí)行結(jié)果如下:

線程池的創(chuàng)建方式有哪些

從上述結(jié)果可以看出,線程池創(chuàng)建了 10  個線程來執(zhí)行相應(yīng)的任務(wù)。

3.SingleThreadExecutor

創(chuàng)建單個線程數(shù)的線程池,它可以保證先進(jìn)先出的執(zhí)行順序。

使用示例如下:

public static void singleThreadExecutor() {     // 創(chuàng)建線程池     ExecutorService threadPool = Executors.newSingleThreadExecutor();     // 執(zhí)行任務(wù)     for (int i = 0; i < 10; i++) {         final int index = i;         threadPool.execute(() -> {             System.out.println(index + ":任務(wù)被執(zhí)行");             try {                 TimeUnit.SECONDS.sleep(1);             } catch (InterruptedException e) {             }         });     } }

執(zhí)行結(jié)果如下:

線程池的創(chuàng)建方式有哪些  

4.ScheduledThreadPool

創(chuàng)建一個可以執(zhí)行延遲任務(wù)的線程池。

使用示例如下:

public static void scheduledThreadPool() {     // 創(chuàng)建線程池     ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(5);     // 添加定時執(zhí)行任務(wù)(1s 后執(zhí)行)     System.out.println("添加任務(wù),時間:" + new Date());     threadPool.schedule(() -> {         System.out.println("任務(wù)被執(zhí)行,時間:" + new Date());         try {             TimeUnit.SECONDS.sleep(1);         } catch (InterruptedException e) {         }     }, 1, TimeUnit.SECONDS); }

執(zhí)行結(jié)果如下:

 線程池的創(chuàng)建方式有哪些

從上述結(jié)果可以看出,任務(wù)在 1  秒之后被執(zhí)行了,符合我們的預(yù)期。

5.SingleThreadScheduledExecutor

創(chuàng)建一個單線程的可以執(zhí)行延遲任務(wù)的線程池。

使用示例如下:

public static void SingleThreadScheduledExecutor() {     // 創(chuàng)建線程池     ScheduledExecutorService threadPool = Executors.newSingleThreadScheduledExecutor();     // 添加定時執(zhí)行任務(wù)(2s 后執(zhí)行)     System.out.println("添加任務(wù),時間:" + new Date());     threadPool.schedule(() -> {         System.out.println("任務(wù)被執(zhí)行,時間:" + new Date());         try {             TimeUnit.SECONDS.sleep(1);         } catch (InterruptedException e) {         }     }, 2, TimeUnit.SECONDS); }

執(zhí)行結(jié)果如下:

線程池的創(chuàng)建方式有哪些

從上述結(jié)果可以看出,任務(wù)在 2  秒之后被執(zhí)行了,符合我們的預(yù)期。

6.newWorkStealingPool

創(chuàng)建一個搶占式執(zhí)行的線程池(任務(wù)執(zhí)行順序不確定),注意此方法只有在 JDK 1.8+ 版本中才能使用。

使用示例如下:

public static void workStealingPool() {     // 創(chuàng)建線程池     ExecutorService threadPool = Executors.newWorkStealingPool();     // 執(zhí)行任務(wù)     for (int i = 0; i < 10; i++) {         final int index = i;         threadPool.execute(() -> {             System.out.println(index + " 被執(zhí)行,線程名:" + Thread.currentThread().getName());         });     }     // 確保任務(wù)執(zhí)行完成     while (!threadPool.isTerminated()) {     } }

執(zhí)行結(jié)果如下:

線程池的創(chuàng)建方式有哪些

從上述結(jié)果可以看出,任務(wù)的執(zhí)行順序是不確定的,因?yàn)樗菗屨际綀?zhí)行的。

7.ThreadPoolExecutor

最原始的創(chuàng)建線程池的方式,它包含了 7 個參數(shù)可供設(shè)置。

使用示例如下:

public static void myThreadPoolExecutor() {     // 創(chuàng)建線程池     ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 100, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10));     // 執(zhí)行任務(wù)     for (int i = 0; i < 10; i++) {         final int index = i;         threadPool.execute(() -> {             System.out.println(index + " 被執(zhí)行,線程名:" + Thread.currentThread().getName());             try {                 Thread.sleep(1000);             } catch (InterruptedException e) {                 e.printStackTrace();             }         });     } }

執(zhí)行結(jié)果如下:

線程池的創(chuàng)建方式有哪些

ThreadPoolExecutor 參數(shù)介紹

ThreadPoolExecutor 最多可以設(shè)置 7 個參數(shù),如下代碼所示:

public ThreadPoolExecutor(int corePoolSize,                            int maximumPoolSize,                            long keepAliveTime,                            TimeUnit unit,                            BlockingQueue workQueue,                            ThreadFactory threadFactory,                            RejectedExecutionHandler handler) {      // 省略...  }

7 個參數(shù)代表的含義如下:

參數(shù) 1:corePoolSize

核心線程數(shù),線程池中始終存活的線程數(shù)。

參數(shù) 2:maximumPoolSize

最大線程數(shù),線程池中允許的最大線程數(shù),當(dāng)線程池的任務(wù)隊(duì)列滿了之后可以創(chuàng)建的最大線程數(shù)。

參數(shù) 3:keepAliveTime

最大線程數(shù)可以存活的時間,當(dāng)線程中沒有任務(wù)執(zhí)行時,最大線程就會銷毀一部分,最終保持核心線程數(shù)量的線程。

參數(shù) 4:unit:

單位是和參數(shù) 3 存活時間配合使用的,合在一起用于設(shè)定線程的存活時間 ,參數(shù) keepAliveTime 的時間單位有以下 7 種可選:

  • TimeUnit.DAYS:天

  • TimeUnit.HOURS:小時

  • TimeUnit.MINUTES:分

  • TimeUnit.SECONDS:秒

  • TimeUnit.MILLISECONDS:毫秒

  • TimeUnit.MICROSECONDS:微妙

  • TimeUnit.NANOSECONDS:納秒

參數(shù) 5:workQueue

一個阻塞隊(duì)列,用來存儲線程池等待執(zhí)行的任務(wù),均為線程安全,它包含以下 7 種類型:

  • ArrayBlockingQueue:一個由數(shù)組結(jié)構(gòu)組成的有界阻塞隊(duì)列。

  • LinkedBlockingQueue:一個由鏈表結(jié)構(gòu)組成的有界阻塞隊(duì)列。

  • SynchronousQueue:一個不存儲元素的阻塞隊(duì)列,即直接提交給線程不保持它們。

  • PriorityBlockingQueue:一個支持優(yōu)先級排序的無界阻塞隊(duì)列。

  • DelayQueue:一個使用優(yōu)先級隊(duì)列實(shí)現(xiàn)的無界阻塞隊(duì)列,只有在延遲期滿時才能從中提取元素。

  • LinkedTransferQueue:一個由鏈表結(jié)構(gòu)組成的無界阻塞隊(duì)列。與SynchronousQueue類似,還含有非阻塞方法。

  • LinkedBlockingDeque:一個由鏈表結(jié)構(gòu)組成的雙向阻塞隊(duì)列。

較常用的是 LinkedBlockingQueue 和 Synchronous,線程池的排隊(duì)策略與 BlockingQueue 有關(guān)。

參數(shù) 6:threadFactory

線程工廠,主要用來創(chuàng)建線程,默認(rèn)為正常優(yōu)先級、非守護(hù)線程。

參數(shù) 7:handler

拒絕策略,拒絕處理任務(wù)時的策略,系統(tǒng)提供了 4 種可選:

  • AbortPolicy:拒絕并拋出異常。

  • CallerRunsPolicy:使用當(dāng)前調(diào)用的線程來執(zhí)行此任務(wù)。

  • DiscardOldestPolicy:拋棄隊(duì)列頭部(最舊)的一個任務(wù),并執(zhí)行當(dāng)前任務(wù)。

  • DiscardPolicy:忽略并拋棄當(dāng)前任務(wù)。

默認(rèn)策略為 AbortPolicy。

線程池的執(zhí)行流程

ThreadPoolExecutor 關(guān)鍵節(jié)點(diǎn)的執(zhí)行流程如下:

  • 當(dāng)線程數(shù)小于核心線程數(shù)時,創(chuàng)建線程。

  • 當(dāng)線程數(shù)大于等于核心線程數(shù),且任務(wù)隊(duì)列未滿時,將任務(wù)放入任務(wù)隊(duì)列。

  • 當(dāng)線程數(shù)大于等于核心線程數(shù),且任務(wù)隊(duì)列已滿:若線程數(shù)小于最大線程數(shù),創(chuàng)建線程;若線程數(shù)等于最大線程數(shù),拋出異常,拒絕任務(wù)。

線程池的執(zhí)行流程如下圖所示:

線程池的創(chuàng)建方式有哪些

線程拒絕策略

我們來演示一下 ThreadPoolExecutor 的拒絕策略的觸發(fā),我們使用 DiscardPolicy  的拒絕策略,它會忽略并拋棄當(dāng)前任務(wù)的策略,實(shí)現(xiàn)代碼如下:

public static void main(String[] args) {     // 任務(wù)的具體方法     Runnable runnable = new Runnable() {         @Override         public void run() {             System.out.println("當(dāng)前任務(wù)被執(zhí)行,執(zhí)行時間:" + new Date() +                                " 執(zhí)行線程:" + Thread.currentThread().getName());             try {                 // 等待 1s                 TimeUnit.SECONDS.sleep(1);             } catch (InterruptedException e) {                 e.printStackTrace();             }         }     };     // 創(chuàng)建線程,線程的任務(wù)隊(duì)列的長度為 1     ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1, 1,                                                            100, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1),                                                            new ThreadPoolExecutor.DiscardPolicy());     // 添加并執(zhí)行 4 個任務(wù)     threadPool.execute(runnable);     threadPool.execute(runnable);     threadPool.execute(runnable);     threadPool.execute(runnable); }

我們創(chuàng)建了一個核心線程數(shù)和最大線程數(shù)都為 1 的線程池,并且給線程池的任務(wù)隊(duì)列設(shè)置為 1,這樣當(dāng)我們有 2  個以上的任務(wù)時就會觸發(fā)拒絕策略,執(zhí)行的結(jié)果如下圖所示:

線程池的創(chuàng)建方式有哪些

從上述結(jié)果可以看出只有兩個任務(wù)被正確執(zhí)行了,其他多余的任務(wù)就被舍棄并忽略了。其他拒絕策略的使用類似,這里就不一一贅述了。

自定義拒絕策略

除了 Java 自身提供的 4 種拒絕策略之外,我們也可以自定義拒絕策略,示例代碼如下:

public static void main(String[] args) {     // 任務(wù)的具體方法     Runnable runnable = new Runnable() {         @Override         public void run() {             System.out.println("當(dāng)前任務(wù)被執(zhí)行,執(zhí)行時間:" + new Date() +                                " 執(zhí)行線程:" + Thread.currentThread().getName());             try {                 // 等待 1s                 TimeUnit.SECONDS.sleep(1);             } catch (InterruptedException e) {                 e.printStackTrace();             }         }     };     // 創(chuàng)建線程,線程的任務(wù)隊(duì)列的長度為 1     ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1, 1,                                                            100, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1),                                                            new RejectedExecutionHandler() {                                                                @Override                                                                public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {                                                                    // 執(zhí)行自定義拒絕策略的相關(guān)操作                                                                    System.out.println("我是自定義拒絕策略~");                                                                }                                                            });     // 添加并執(zhí)行 4 個任務(wù)     threadPool.execute(runnable);     threadPool.execute(runnable);     threadPool.execute(runnable);     threadPool.execute(runnable); }

程序的執(zhí)行結(jié)果如下:

線程池的創(chuàng)建方式有哪些  

究竟選用哪種線程池?

經(jīng)過以上的學(xué)習(xí)我們對整個線程池也有了一定的認(rèn)識了,那究竟該如何選擇線程池呢?

我們來看下阿里巴巴《Java開發(fā)手冊》給我們的答案:

  • 【強(qiáng)制】線程池不允許使用 Executors 去創(chuàng)建,而是通過 ThreadPoolExecutor  的方式,這樣的處理方式讓寫的同學(xué)更加明確線程池的運(yùn)行規(guī)則,規(guī)避資源耗盡的風(fēng)險。

  • 說明:Executors 返回的線程池對象的弊端如下:

  • 1) FixedThreadPool 和 SingleThreadPool:允許的請求隊(duì)列長度為  Integer.MAX_VALUE,可能會堆積大量的請求,從而導(dǎo)致 OOM。

  • 2)CachedThreadPool:允許的創(chuàng)建線程數(shù)量為 Integer.MAX_VALUE,可能會創(chuàng)建大量的線程,從而導(dǎo)致 OOM。

  • 所以綜上情況所述,我們推薦使用 ThreadPoolExecutor  的方式進(jìn)行線程池的創(chuàng)建,因?yàn)檫@種創(chuàng)建方式更可控,并且更加明確了線程池的運(yùn)行規(guī)則,可以規(guī)避一些未知的風(fēng)險。

感謝各位的閱讀,以上就是“線程池的創(chuàng)建方式有哪些”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對線程池的創(chuàng)建方式有哪些這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!


標(biāo)題名稱:線程池的創(chuàng)建方式有哪些
新聞來源:http://weahome.cn/article/ihscss.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部