這篇文章主要介紹“使用Java線程池的方法步驟”,在日常操作中,相信很多人在使用Java線程池的方法步驟問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”使用Java線程池的方法步驟”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!
創(chuàng)新互聯(lián)公司是專業(yè)的廣豐網(wǎng)站建設(shè)公司,廣豐接單;提供成都網(wǎng)站建設(shè)、成都網(wǎng)站制作,網(wǎng)頁設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行廣豐網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!
1.頻繁創(chuàng)建和銷毀單個(gè)線程,浪費(fèi)資源,并且還會(huì)出現(xiàn)頻繁GC
2.缺乏統(tǒng)一管理,各線程相互競(jìng)爭(zhēng)
ThreadPoolExecutor有四個(gè)重載的構(gòu)造方法,我們這里來說說參數(shù)最多的那一個(gè)重載的構(gòu)造方法,這樣大家就知道其他方法參數(shù)的含義了,如下:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
各參數(shù)詳細(xì)說明:
這里是7個(gè)參數(shù)(我們?cè)陂_發(fā)中用的更多的是5個(gè)參數(shù)的構(gòu)造方法),OK,那我們來看看這里七個(gè)參數(shù)的含義:
corePoolSize 線程池中核心線程的數(shù)量
maximumPoolSize 線程池中最大線程數(shù)量
keepAliveTime 非核心線程的超時(shí)時(shí)長(zhǎng),當(dāng)系統(tǒng)中非核心線程閑置時(shí)間超過keepAliveTime之后,則會(huì)被回收。如果ThreadPoolExecutor的allowCoreThreadTimeOut屬性設(shè)置為true,則該參數(shù)也表示核心線程的超時(shí)時(shí)長(zhǎng)
unit 第三個(gè)參數(shù)的單位,有納秒、微秒、毫秒、秒、分、時(shí)、天等
workQueue 線程池中的任務(wù)隊(duì)列,該隊(duì)列主要用來存儲(chǔ)已經(jīng)被提交但是尚未執(zhí)行的任務(wù)。存儲(chǔ)在這里的任務(wù)是由ThreadPoolExecutor的execute方法提交來的。
threadFactory 為線程池提供創(chuàng)建新線程的功能,這個(gè)我們一般使用默認(rèn)即可
handler 拒絕策略,當(dāng)線程無法執(zhí)行新任務(wù)時(shí)(一般是由于線程池中的線程數(shù)量已經(jīng)達(dá)到最大數(shù)或者線程池關(guān)閉導(dǎo)致的),默認(rèn)情況下,當(dāng)線程池?zé)o法處理新線程時(shí),會(huì)拋出一個(gè)RejectedExecutionException。
workQueue介紹
1.ArrayBlockingQueue:這個(gè)表示一個(gè)規(guī)定了大小的BlockingQueue,ArrayBlockingQueue的構(gòu)造函數(shù)接受一個(gè)int類型的數(shù)據(jù),該數(shù)據(jù)表示BlockingQueue的大小,存儲(chǔ)在ArrayBlockingQueue中的元素按照FIFO(先進(jìn)先出)的方式來進(jìn)行存取。
2.LinkedBlockingQueue:這個(gè)表示一個(gè)大小不確定的BlockingQueue,在LinkedBlockingQueue的構(gòu)造方法中可以傳一個(gè)int類型的數(shù)據(jù),這樣創(chuàng)建出來的LinkedBlockingQueue是有大小的,也可以不傳,不傳的話,LinkedBlockingQueue的大小就為Integer.MAX_VALUE,源碼如下:
3.PriorityBlockingQueue:這個(gè)隊(duì)列和LinkedBlockingQueue類似,不同的是PriorityBlockingQueue中的元素不是按照FIFO來排序的,而是按照元素的Comparator來決定存取順序的(這個(gè)功能也反映了存入PriorityBlockingQueue中的數(shù)據(jù)必須實(shí)現(xiàn)了Comparator接口)。
4.SynchronousQueue:這個(gè)是同步Queue,屬于線程安全的BlockingQueue的一種,在SynchronousQueue中,生產(chǎn)者線程的插入操作必須要等待消費(fèi)者線程的移除操作,Synchronous內(nèi)部沒有數(shù)據(jù)緩存空間,因此我們無法對(duì)SynchronousQueue進(jìn)行讀取或者遍歷其中的數(shù)據(jù),元素只有在你試圖取走的時(shí)候才有可能存在。我們可以理解為生產(chǎn)者和消費(fèi)者互相等待,等到對(duì)方之后然后再一起離開。
拒絕策略
AbortPolicy:直接拒絕,并拋出異常,這也是默認(rèn)的策略。
CallerRunsPolicy:直接讓調(diào)用execute方法的線程去執(zhí)行此任務(wù)。
DiscardOldestPolicy:丟棄最老的未處理的任務(wù),然后重新嘗試執(zhí)行當(dāng)前的新任務(wù)。
DiscardPolicy:直接丟棄當(dāng)前任務(wù),但是不拋異常
當(dāng)線程數(shù)量未達(dá)到corePoolSize的時(shí)候,就會(huì)創(chuàng)建新的線程來執(zhí)行任務(wù)。
當(dāng)核心線程數(shù)已滿,就會(huì)把任務(wù)放到阻塞隊(duì)列。
當(dāng)隊(duì)列已滿,并且未達(dá)到最大線程數(shù),就會(huì)新建非核心線程來執(zhí)行任務(wù)(重要)。
當(dāng)隊(duì)列已滿,并且達(dá)到了最大線程數(shù),則選擇一種拒絕策略來執(zhí)行。
1.FixedThreadPool
固定大小的線程池,可以指定線程池的大小,該線程池corePoolSize和maximumPoolSize相等,阻塞隊(duì)列使用的是LinkedBlockingQueue,大小為整數(shù)最大值。
該線程池中的線程數(shù)量始終不變,當(dāng)有新任務(wù)提交時(shí),線程池中有空閑線程則會(huì)立即執(zhí)行,如果沒有,則會(huì)暫存到阻塞隊(duì)列。對(duì)于固定大小的線程池,不存在線程數(shù)量的變化。
同時(shí)使用無界的LinkedBlockingQueue來存放執(zhí)行的任務(wù)。當(dāng)任務(wù)提交十分頻繁的時(shí)候,LinkedBlockingQueue迅速增大,存在著耗盡系統(tǒng)資源的問題。
而且在線程池空閑時(shí),即線程池中沒有可運(yùn)行任務(wù)時(shí),它也不會(huì)釋放工作線程,還會(huì)占用一定的系統(tǒng)資源,需要shutdown
2.SingleThreadExecutor
可以看到阻塞隊(duì)例 使用的是LinkedBolckingQueue,且默認(rèn)大小為Integer.MAX_VALUE,這樣的話,如果有大量請(qǐng)求到來,會(huì)放入到這個(gè)任務(wù)隊(duì)列里,可能會(huì)導(dǎo)致OOM;
3.Executors.newCachedThreadPool()
可緩存線程池,先查看線程池中有沒有以前建立的線程,如果有就直接使用,如果沒有新建一個(gè)線程加入線程池中,可緩存線程池
通常用于執(zhí)行一些生存期很短的異步型任務(wù);線程池為無限大,當(dāng)執(zhí)行當(dāng)前任務(wù)時(shí)上一個(gè)任務(wù)已經(jīng)完成,會(huì)復(fù)用執(zhí)行上一個(gè)任務(wù)的線程,而不用每次新建線程
緩存的線程默認(rèn)存活60秒。線程的核心池corePoolSize大小為0,核心池最大為Integer.MAX_VALUE,阻塞隊(duì)列使用的是SynchronousQueue。
是一個(gè)直接提交的阻塞隊(duì)列,他總會(huì)迫使線程池增加新的線程去執(zhí)行新的任務(wù)。
在沒有任務(wù)執(zhí)行時(shí),當(dāng)線程的空閑時(shí)間超過keepAliveTime(60秒),則工作線程將會(huì)終止被回收,當(dāng)提交新任務(wù)時(shí),
如果沒有空閑線程,則創(chuàng)建新線程執(zhí)行任務(wù),會(huì)導(dǎo)致一定的系統(tǒng)開銷。
如果同時(shí)又大量任務(wù)被提交,而且任務(wù)執(zhí)行的時(shí)間不是特別快,那么線程池便會(huì)新增出等量的線程池處理任務(wù),這很可能會(huì)很快耗盡系統(tǒng)的資源。
4.ScheduledThreadPool
創(chuàng)建一個(gè)定長(zhǎng)線程池,支持定時(shí)及周期性任務(wù)執(zhí)行
定時(shí)線程池,該線程池可用于周期性地去執(zhí)行任務(wù),通常用于周期性的同步數(shù)據(jù)。
scheduleAtFixedRate:是以固定的頻率去執(zhí)行任務(wù),周期是指每次執(zhí)行任務(wù)成功執(zhí)行之間的間隔。
schedultWithFixedDelay:是以固定的延時(shí)去執(zhí)行任務(wù),延時(shí)是指上一次執(zhí)行成功之后和下一次開始執(zhí)行的之前的時(shí)間。
通過上述源碼分析,我們發(fā)現(xiàn)newFixedThreadPool和newSingleThreadExecutor方法他們都使用了LinkedBlockingQueue的任務(wù)隊(duì)列,LinkedBlockingQueue的默認(rèn)大小為Integer.MAX_VALUE。而newCachedThreadPool中定義的線程池大小為Integer.MAX_VALUE。
所以阿里禁止使用Executors創(chuàng)建線程池的原因就是FixedThreadPool和SingleThreadPool的請(qǐng)求隊(duì)列長(zhǎng)度為Integer.MAX_VALUE,可能會(huì)堆積大量的請(qǐng)求,從而導(dǎo)致OOM。
CachedThreadPool允許的創(chuàng)建線程數(shù)量為Integer.MAX_VALUE,可能會(huì)創(chuàng)建大量的線程,從而導(dǎo)致OOM。
1.shutDown() 關(guān)閉線程池,不影響已經(jīng)提交的任務(wù)
2.shutDownNow() 關(guān)閉線程池,并嘗試去終止正在執(zhí)行的線程
3.allowCoreThreadTimeOut(boolean value) 允許核心線程閑置超時(shí)時(shí)被回收
4.單例模式創(chuàng)建線程池
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.*;
/**
* 異步任務(wù)處理器
*/
public class AsyncTaskExecutor {
/** 線程池保持ALIVE狀態(tài)線程數(shù) */
public static final int CORE_POOL_SIZE = 10;
/** 線程池最大線程數(shù) */
public static final int MAX_POOL_SIZE = 40;
/** 空閑線程回收時(shí)間 */
public static final int KEEP_ALIVE_TIME = 1000;
/** 線程池等待隊(duì)列 */
public static final int BLOCKING_QUEUE_SIZE = 1000;
/** 業(yè)務(wù)請(qǐng)求異步處理線程池 */
private static final ThreadPoolExecutor processExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.MICROSECONDS,
new LinkedBlockingQueue
new TreadFactoryBuilder.setNameFormat("boomoom-thread-pool-%d").build(),
new TreadPoolExecutor.DiscardPolicy());
private AsyncTaskExecutor() {};
/**
* 異步任務(wù)處理
*
* @param task 任務(wù)
*/
public void execute(Runnable task) {
processExecutor.submit(task);
}
}
懶漢式和饑漢式區(qū)別
1.餓漢式是線程安全的,在類創(chuàng)建的同時(shí)就已經(jīng)創(chuàng)建好一個(gè)靜態(tài)的對(duì)象供系統(tǒng)使用,以后不再改變。
2.懶漢式如果想要線程安全必須用雙重檢驗(yàn)鎖并且對(duì)象還必須是volatile,防止對(duì)象指令重排
到此,關(guān)于“使用Java線程池的方法步驟”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!