目錄
- 前言
- 1. 概念
- 2. 線程池相關參數
- 3. Executors的使用
- 總結
前言
線程是為了解決進程太重的問題,操作系統中進程的創建和銷毀需要較多的系統資源,用了輕量級的線程來代替部分線程,但是如果線程創建和銷毀的頻率也開始提升到了一定程度,系統的開銷同樣也不可忽視了,為了解決這種問題,我們使用了線程池進行優化。本篇文章就主要來講講線程池。
1. 概念
我們提前把線程創建好,放到一個”池子“里,這就構成了一個線程池,我們在申請線程時,直接從這個所謂的池子里取,用完了之后再放回去,這就是線程池的基本思想,很好的減小了創建和銷毀的線程的開銷。
2. 線程池相關參數
這里主要介紹一下線程池構造方法中的相關參數。
Java中提供了線程池的類:ThreadPoolExecutor,在創建這個類的實例時,有很多參數,這里來簡要介紹一下:
官方文檔中,有這四種構造方式,我們介紹第四個,其中包含了前三個的參數。
我們先看前兩個參數:
第一個表示核心線程數,第二個表示總數。
在Java的線程池中,把線程分為兩種:核心線程和臨時線程,一創建就申請的線程是核心線程,將任務交給核心線程。若核心線程被占用滿,處理不過來,就會申請一些臨時的線程來進行“協助”,當空閑下來時,這些臨時線程被釋放,但是核心線程不會被釋放。
接下來看:
這里第一個表示線程的存活時間,第二個表示時間單位。
通過這兩個參數,來設定臨時線程的存活時間。
接下來:
這里的參數是一個阻塞隊列,存放著線程池的任務隊列, 線程池就是從這個隊列中取出任務,分配給其創建的線程。
繼續看下一個參數:
這是一個線程工廠,這里的線程工廠使用了工廠設計模式,這是眾多設計模式中很常見的一種,工廠模式用于彌補構造方法里存在的缺陷,比如說在創建多個構造方法的時候,如果參數的數量一致,那么參數的類型需要不同,但是實際中常常需要上述創建這種情況的構造方法,這里的參數含義不同,但是類型和數量卻是一致,這樣構造會編譯出錯。
所以為了解決這種問題,我們就引用了工廠設計模式,在這個設計模式里,我們不用構造方法來初始化對象,使用靜態方法來初始化對象,即創建一個工廠類,在里面構造靜態方法,來間接的達到創建對象的目的。
回到線程工廠,我們使用這個線程工廠,則是用來對線程池所創建出來的線程進行初始化的設定。
下面看最后一個參數:
此參數叫做拒絕策略,當線程池的任務隊列滿的時候,如果再次添加新任務,則會根據給出的拒絕策略來進行處理,文檔提供了四種拒絕策略。
第一個叫做直接終止,即拋出異常,終止程序。
第二個是讓調用者自己來執行任務。
第三個是丟棄隊列中最老任務。
第四個是丟棄隊列中最新任務。
3. Executors的使用
Executors是標準庫中提供的一個線程池的簡化版本,即對ThreadPoolExecutot進行了封裝。
我們可以使用Executor來創建一些線程池:
可以看到這里有各種各樣的線程池。
下面介紹四個常用的:
public static void main(String[] args) {//固定線程數目的線程池,核心線程和最大線程數都是4ExecutorService service = Executors.newFixedThreadPool(4);//核心線程數為0,最大線程數為Integer.MAX_VALUE的線程池ExecutorService service2 = Executors.newCachedThreadPool();// 只有一個線程的線程池,核心線程數和最大線程數都是1ExecutorService service3 = Executors.newSingleThreadExecutor();// “定時器”,核心線程數為0,最大線程數為10的線程池,在這個線程池的任務可以在一定時間后執行或定期執行ExecutorService service4 = Executors.newScheduledThreadPool(10);}
一般來說我們使用最多的線程池是前兩個,接下來展示如何添加任務:
for (int i = 0; i < 100; i++) {int id = i;service.submit( new Runnable(){@Overridepublic void run() {System.out.println("線程池中的線程正在執行任務" + id);}});}
運行效果:
總結
以上是對線程池的一些基本介紹,希望能夠讓大家了解Java中線程池各參數的作用并且能夠使用Executors創建常見的線程池。