java高级应用:线程池全面解析
?
什么是線程池?
很簡單,簡單看名字就知道是裝有線程的池子,我們可以把要執(zhí)行的多線程交給線程池來處理,和連接池的概念一樣,通過維護(hù)一定數(shù)量的線程池來達(dá)到多個(gè)線程的復(fù)用。
?
線程池的好處
我們知道不用線程池的話,每個(gè)線程都要通過new Thread(xxRunnable).start()的方式來創(chuàng)建并運(yùn)行一個(gè)線程,線程少的話這不會(huì)是問題,而真實(shí)環(huán)境可能會(huì)開啟多個(gè)線程讓系統(tǒng)和程序達(dá)到最佳效率,當(dāng)線程數(shù)達(dá)到一定數(shù)量就會(huì)耗盡系統(tǒng)的CPU和內(nèi)存資源,也會(huì)造成GC頻繁收集和停頓,因?yàn)槊看蝿?chuàng)建和銷毀一個(gè)線程都是要消耗系統(tǒng)資源的,如果為每個(gè)任務(wù)都創(chuàng)建線程這無疑是一個(gè)很大的性能瓶頸。所以,線程池中的線程復(fù)用極大節(jié)省了系統(tǒng)資源,當(dāng)線程一段時(shí)間不再有任務(wù)處理時(shí)它也會(huì)自動(dòng)銷毀,而不會(huì)長駐內(nèi)存。
?
線程池核心類
在java.util.concurrent包中我們能找到線程池的定義,其中ThreadPoolExecutor是我們線程池核心類,首先看看線程池類的主要參數(shù)有哪些。
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||keepAliveTime < 0)throw new IllegalArgumentException();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;}-
corePoolSize:線程池的核心大小,也可以理解為最小的線程池大小。
-
maximumPoolSize:最大線程池大小。
-
keepAliveTime:空余線程存活時(shí)間,指的是超過corePoolSize的空余線程達(dá)到多長時(shí)間才進(jìn)行銷毀。
-
unit:銷毀時(shí)間單位。
-
workQueue:存儲(chǔ)等待執(zhí)行線程的工作隊(duì)列。
-
threadFactory:創(chuàng)建線程的工廠,一般用默認(rèn)即可。
-
handler:拒絕策略,當(dāng)工作隊(duì)列、線程池全已滿時(shí)如何拒絕新任務(wù),默認(rèn)拋出異常。
?
線程池工作流程
1、如果線程池中的線程小于corePoolSize時(shí)就會(huì)創(chuàng)建新線程直接執(zhí)行任務(wù)。
2、如果線程池中的線程大于corePoolSize時(shí)就會(huì)暫時(shí)把任務(wù)存儲(chǔ)到工作隊(duì)列workQueue中等待執(zhí)行。
3、如果工作隊(duì)列workQueue也滿時(shí):當(dāng)線程數(shù)小于最大線程池?cái)?shù)maximumPoolSize時(shí)就會(huì)創(chuàng)建新線程來處理,而線程數(shù)大于等于最大線程池?cái)?shù)maximumPoolSize時(shí)就會(huì)執(zhí)行拒絕策略。
?
線程池分類
Executors是jdk里面提供的創(chuàng)建線程池的工廠類,它默認(rèn)提供了4種常用的線程池應(yīng)用,而不必我們?nèi)ブ貜?fù)構(gòu)造。
-
newFixedThreadPool
固定線程池,核心線程數(shù)和最大線程數(shù)固定相等,而空閑存活時(shí)間為0毫秒,說明此參數(shù)也無意義,工作隊(duì)列為最大為Integer.MAX_VALUE大小的阻塞隊(duì)列。當(dāng)執(zhí)行任務(wù)時(shí),如果線程都很忙,就會(huì)丟到工作隊(duì)列等有空閑線程時(shí)再執(zhí)行,隊(duì)列滿就執(zhí)行默認(rèn)的拒絕策略。
?
-
newCachedThreadPool
? ? ? ? 帶緩沖線程池,從構(gòu)造看核心線程數(shù)為0,最大線程數(shù)為Integer最大值大小,超過0個(gè)的空閑線程在60秒后銷毀,SynchronousQueue這是一個(gè)直接提交的隊(duì)列,意味著每個(gè)新任務(wù)都會(huì)有線程來執(zhí)行,如果線程池有可用線程則執(zhí)行任務(wù),沒有的話就創(chuàng)建一個(gè)來執(zhí)行,線程池中的線程數(shù)不確定,一般建議執(zhí)行速度較快較小的線程,不然這個(gè)最大線程池邊界過大容易造成內(nèi)存溢出。
/*** Creates a thread pool that creates new threads as needed, but* will reuse previously constructed threads when they are* available. These pools will typically improve the performance* of programs that execute many short-lived asynchronous tasks.* Calls to {@code execute} will reuse previously constructed* threads if available. If no existing thread is available, a new* thread will be created and added to the pool. Threads that have* not been used for sixty seconds are terminated and removed from* the cache. Thus, a pool that remains idle for long enough will* not consume any resources. Note that pools with similar* properties but different details (for example, timeout parameters)* may be created using {@link ThreadPoolExecutor} constructors.** @return the newly created thread pool*/public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}?
-
newSingleThreadExecutor
????????單線程線程池,核心線程數(shù)和最大線程數(shù)均為1,空閑線程存活0毫秒同樣無意思,意味著每次只執(zhí)行一個(gè)線程,多余的先存儲(chǔ)到工作隊(duì)列,一個(gè)一個(gè)執(zhí)行,保證了線程的順序執(zhí)行。
/*** Creates an Executor that uses a single worker thread operating* off an unbounded queue. (Note however that if this single* thread terminates due to a failure during execution prior to* shutdown, a new one will take its place if needed to execute* subsequent tasks.) Tasks are guaranteed to execute* sequentially, and no more than one task will be active at any* given time. Unlike the otherwise equivalent* {@code newFixedThreadPool(1)} the returned executor is* guaranteed not to be reconfigurable to use additional threads.** @return the newly created single-threaded Executor*/public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));}?
-
newScheduledThreadPool
調(diào)度線程池,即按一定的周期執(zhí)行任務(wù),即定時(shí)任務(wù),對ThreadPoolExecutor進(jìn)行了包裝而已。
?
拒絕策略
-
AbortPolicy
??????簡單粗暴,直接拋出拒絕異常,這也是默認(rèn)的拒絕策略。
/*** A handler for rejected tasks that throws a* {@code RejectedExecutionException}.*/public static class AbortPolicy implements RejectedExecutionHandler {/*** Creates an {@code AbortPolicy}.*/public AbortPolicy() { }/*** Always throws RejectedExecutionException.** @param r the runnable task requested to be executed* @param e the executor attempting to execute this task* @throws RejectedExecutionException always*/public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {throw new RejectedExecutionException("Task " + r.toString() +" rejected from " +e.toString());}} /*** The default rejected execution handler*/private static final RejectedExecutionHandler defaultHandler =new AbortPolicy();?
-
CallerRunsPolicy? ? ?
???????如果線程池未關(guān)閉,則會(huì)在調(diào)用者線程中直接執(zhí)行新任務(wù),這會(huì)導(dǎo)致主線程提交線程性能變慢。
/*** A handler for rejected tasks that runs the rejected task* directly in the calling thread of the {@code execute} method,* unless the executor has been shut down, in which case the task* is discarded.*/public static class CallerRunsPolicy implements RejectedExecutionHandler {/*** Creates a {@code CallerRunsPolicy}.*/public CallerRunsPolicy() { }/*** Executes task r in the caller's thread, unless the executor* has been shut down, in which case the task is discarded.** @param r the runnable task requested to be executed* @param e the executor attempting to execute this task*/public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {if (!e.isShutdown()) {r.run();}}}?
-
DiscardPolicy
????? ?從方法看沒做任務(wù)操作,即表示不處理新任務(wù),即丟棄。
/*** A handler for rejected tasks that silently discards the* rejected task.*/public static class DiscardPolicy implements RejectedExecutionHandler {/*** Creates a {@code DiscardPolicy}.*/public DiscardPolicy() { }/*** Does nothing, which has the effect of discarding task r.** @param r the runnable task requested to be executed* @param e the executor attempting to execute this task*/public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {}}?
-
DiscardOldestPolicy
????? ?拋棄最老的任務(wù),就是從隊(duì)列取出最老的任務(wù)然后放入新的任務(wù)進(jìn)行執(zhí)行。? ? ? ??
/*** A handler for rejected tasks that discards the oldest unhandled* request and then retries {@code execute}, unless the executor* is shut down, in which case the task is discarded.*/public static class DiscardOldestPolicy implements RejectedExecutionHandler {/*** Creates a {@code DiscardOldestPolicy} for the given executor.*/public DiscardOldestPolicy() { }/*** Obtains and ignores the next task that the executor* would otherwise execute, if one is immediately available,* and then retries execution of task r, unless the executor* is shut down, in which case task r is instead discarded.** @param r the runnable task requested to be executed* @param e the executor attempting to execute this task*/public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {if (!e.isShutdown()) {e.getQueue().poll();e.execute(r);}}}?
如何提交線程
如可以先隨便定義一個(gè)固定大小的線程池
ExecutorService es = Executors.newFixedThreadPool(3);提交一個(gè)線程
es.submit(xxRunnble); es.execute(xxRunnble);submit和execute分別有什么區(qū)別呢?
execute沒有返回值,如果不需要知道線程的結(jié)果就使用execute方法,性能會(huì)好很多。
submit返回一個(gè)Future對象,如果想知道線程結(jié)果就使用submit提交,而且它能在主線程中通過Future的get方法捕獲線程中的異常。
?
如何關(guān)閉線程池
es.shutdown();?不再接受新的任務(wù),之前提交的任務(wù)等執(zhí)行結(jié)束再關(guān)閉線程池。
?
es.shutdownNow();不再接受新的任務(wù),試圖停止池中的任務(wù)再關(guān)閉線程池,返回所有未處理的線程list列表。
總結(jié)
以上是生活随笔為你收集整理的java高级应用:线程池全面解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: volatile关键字解析~高级java
- 下一篇: 并发控制--悲观锁和乐观锁详解