概述
多線程技術(shù)主要解決處理器單元內(nèi)多個線程執(zhí)行的問題,它可以顯著減少處理器單元的閑置時間,增加處理器單元的吞吐能力。
假設(shè)一個服務(wù)器完成一項(xiàng)任務(wù)所需時間為:T1 創(chuàng)建線程時間,T2 在線程中執(zhí)行任務(wù)的時間,T3 銷毀線程時間。
如果:T1 + T3 遠(yuǎn)大于 T2,則可以采用線程池,以提高服務(wù)器性能。
一個線程池包括以下四個基本組成部分:
- 線程池管理器(ThreadPool):用于創(chuàng)建并管理線程池,包括 創(chuàng)建線程池,銷毀線程池,添加新任務(wù);
- 工作線程(PoolWorker):線程池中線程,在沒有任務(wù)時處于等待狀態(tài),可以循環(huán)的執(zhí)行任務(wù);
- 任務(wù)接口(Task):每個任務(wù)必須實(shí)現(xiàn)的接口,以供工作線程調(diào)度任務(wù)的執(zhí)行,它主要規(guī)定了任務(wù)的入口,任務(wù)執(zhí)行完后的收尾工作,任務(wù)的執(zhí)行狀態(tài)等;
- 任務(wù)隊(duì)列(taskQueue):用于存放沒有處理的任務(wù)。提供一種緩沖機(jī)制。
線程池技術(shù)正是關(guān)注如何縮短或調(diào)整T1,T3時間的技術(shù),從而提高服務(wù)器程序性能的。
它把T1,T3分別安排在服務(wù)器程序的啟動和結(jié)束的時間段或者一些空閑的時間段,這樣在服務(wù)器程序處理客戶請求時,不會有T1,T3的開銷了。
線程池不僅調(diào)整T1,T3產(chǎn)生的時間段,而且它還顯著減少了創(chuàng)建線程的數(shù)目,看一個例子:
假設(shè)一個服務(wù)器一天要處理50000個請求,并且每個請求需要一個單獨(dú)的線程完成。在線程池中,線程數(shù)一般是固定的,所以產(chǎn)生線程總數(shù)不會超過線程池中線程的數(shù)目,而如果服務(wù)器不利用線程池來處理這些請求則線程總數(shù)為50000。一般線程池大小是遠(yuǎn)小于50000。所以利用線程池的服務(wù)器程序不會為了創(chuàng)建50000而在處理請求時浪費(fèi)時間,從而提高效率。
線程的使用在java中占有極其重要的地位,在jdk1.4極其之前的jdk版本中,關(guān)于線程池的使用是極其簡陋的。在jdk1.5之后這一情況有了很大的改觀。Jdk1.5之后加入了java.util.concurrent包,這個包中主要介紹java中線程以及線程池的使用。為我們在開發(fā)中處理線程的問題提供了非常大的幫助。
為什么要使用線程池
- 1.創(chuàng)建/銷毀線程伴隨著系統(tǒng)開銷,過于頻繁的創(chuàng)建/銷毀線程,會很大程度上影響處-理效率
- 2.可以根據(jù)系統(tǒng)的承受能力,調(diào)整線程池中工作線線程的數(shù)目,防止因?yàn)橄倪^多的內(nèi)存,而把服務(wù)器累趴下(每個線程需要大約1MB內(nèi)存,線程開的越多,消耗的內(nèi)存也就越大,最后死機(jī))
- 3.對線程進(jìn)行一些簡單的管理
ThreadPoolExecutor
Java里面線程池的頂級接口是Executor,但是嚴(yán)格意義上講Executor并不是一個線程池,而只是一個執(zhí)行線程的工具。
真正的線程池接口是ExecutorService。即:ExecutorService接口是Executor的子接口,而ThreadPoolExecutor實(shí)現(xiàn)了ExecutorService,是具體的實(shí)現(xiàn)類:
學(xué)習(xí)Java中的線程池,就可以直接學(xué)習(xí)ThreadPoolExecutor,對線程池的配置就是對ThreadPoolExecutor構(gòu)造函數(shù)的參數(shù)的配置:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
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.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
各個參數(shù)的含義:
-
int corePoolSize:該線程池中核心線程數(shù)最大值
核心線程:線程池新建線程的時候,如果當(dāng)前線程總數(shù)小于corePoolSize,則新建的是核心線程,如果超過corePoolSize,則新建的是非核心線程,核心線程默認(rèn)情況下會一直存活在線程池中,即使這個核心線程啥也不干(閑置狀態(tài))。
如果指定ThreadPoolExecutor的allowCoreThreadTimeOut這個屬性為true,那么核心線程如果不干活(閑置狀態(tài))的話,超過一定時間(時長下面參數(shù)決定),就會被銷毀掉。 -
int maximumPoolSize: 該線程池中線程總數(shù)最大值
線程總數(shù) = 核心線程數(shù) + 非核心線程數(shù)。 -
long keepAliveTime:該線程池中非核心線程閑置超時時長
一個非核心線程,如果不干活(閑置狀態(tài))的時長超過這個參數(shù)所設(shè)定的時長,就會被銷毀掉,如果設(shè)置allowCoreThreadTimeOut = true,則同樣會作用于核心線程。 -
TimeUnit unit:keepAliveTime的單位
TimeUnit是一個枚舉類型,其包括:
NANOSECONDS : 1微毫秒 = 1微秒 / 1000
MICROSECONDS : 1微秒 = 1毫秒 / 1000
MILLISECONDS : 1毫秒 = 1秒 /1000
SECONDS : 秒
MINUTES : 分
HOURS : 小時
DAYS : 天
-
BlockingQueue workQueue:該線程池中的任務(wù)隊(duì)列:維護(hù)著等待執(zhí)行的Runnable對象
當(dāng)所有的核心線程
都在干活時,新添加的任務(wù)會被添加到這個隊(duì)列中等待處理,如果隊(duì)列滿了,則新建非核心線程執(zhí)行任務(wù)。
常用的workQueue類型:
1.SynchronousQueue:
這個隊(duì)列接收到任務(wù)的時候,會直接提交給線程處理,而不保留它。
如果所有線程都在工作怎么辦?
那就新建一個線程來處理這個任務(wù)!所以為了保證不出現(xiàn)<線程數(shù)達(dá)到了maximumPoolSize而不能新建線程>的錯誤,使用這個類型隊(duì)列的時候,maximumPoolSize一般指定成Integer.MAX_VALUE,即無限大。
2.LinkedBlockingQueue:
這個隊(duì)列接收到任務(wù)的時候,如果當(dāng)前線程數(shù)小于核心線程數(shù),則新建線程(核心線程)處理任務(wù);如果當(dāng)前線程數(shù)等于核心線程數(shù),則進(jìn)入隊(duì)列等待。由于這個隊(duì)列默認(rèn)大小為Integer.MAX_VALUE,即所有超過核心線程數(shù)的任務(wù)都將被添加到隊(duì)列中,所以如果未通過構(gòu)造方法設(shè)置隊(duì)列長度就會導(dǎo)致maximumPoolSize的設(shè)定失效,因?yàn)榭偩€程數(shù)永遠(yuǎn)不會超過corePoolSize。
3.ArrayBlockingQueue:
可以限定隊(duì)列的長度,接收到任務(wù)的時候,如果沒有達(dá)到corePoolSize的值,則新建線程(核心線程)執(zhí)行任務(wù),如果達(dá)到了,則入隊(duì)等候,如果隊(duì)列已滿,則新建線程(非核心線程)執(zhí)行任務(wù),又如果總線程數(shù)到了maximumPoolSize,并且隊(duì)列也滿了,則發(fā)生錯誤。
4.DelayQueue:
隊(duì)列內(nèi)元素必須實(shí)現(xiàn)Delayed接口,這就意味著你傳進(jìn)去的任務(wù)必須先實(shí)現(xiàn)Delayed接口。這個隊(duì)列接收到任務(wù)時,首先先入隊(duì),只有達(dá)到了指定的延時時間,才會執(zhí)行任務(wù)。
如何向ThreadPoolExecutor添加任務(wù)
通過ThreadPoolExecutor.execute(Runnable command)方法即可向線程池內(nèi)添加一個任務(wù)。
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
RejectedExecutionHandler拒絕策略
RejectedExecutionHandler是一個接口,當(dāng)要創(chuàng)建的線程數(shù)量大于線程池的最大線程數(shù)的時候,新的任務(wù)就會被拒絕,就會調(diào)用這個接口里的rejectedExecution方法:
package java.util.concurrent;
/**
* A handler for tasks that cannot be executed by a {@link ThreadPoolExecutor}.
*
* @since 1.5
* @author Doug Lea
*/
public interface RejectedExecutionHandler {
/**
* Method that may be invoked by a {@link ThreadPoolExecutor} when
* {@link ThreadPoolExecutor#execute execute} cannot accept a
* task. This may occur when no more threads or queue slots are
* available because their bounds would be exceeded, or upon
* shutdown of the Executor.
*
* <p>In the absence of other alternatives, the method may throw
* an unchecked {@link RejectedExecutionException}, which will be
* propagated to the caller of {@code execute}.
*
* @param r the runnable task requested to be executed
* @param executor the executor attempting to execute this task
* @throws RejectedExecutionException if there is no remedy
*/
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
Java中為我們提供了4種拒絕策略:
-
AbortPolicy
ThreadPoolExecutor中默認(rèn)的拒絕策略就是AbortPolicy,直接拋出異常。
源碼如下:
/**
* 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());
}
}
簡單粗暴,直接拋出個RejectedExecutionException異常,也不執(zhí)行這個任務(wù)了。
-
CallerRunsPolicy
CallerRunsPolicy在任務(wù)被拒絕添加后,會調(diào)用當(dāng)前線程池的所在的線程去執(zhí)行被拒絕的任務(wù)。
源碼如下:
/**
* 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ù)直接拋棄,不會拋異常也不會執(zhí)行。
源碼如下:
/**
* 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
DiscardOldestPolicy策略的作用是:當(dāng)任務(wù)被拒絕添加時,會拋棄任務(wù)隊(duì)列中最舊的任務(wù)也就是最先加入隊(duì)列的,再把這個新任務(wù)添加進(jìn)去。
源碼如下:
/**
* 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);
}
}
}
當(dāng)然我們也可以自定義拒絕策略,只需要實(shí)現(xiàn)RejectedExecutionHandler接口并重寫rejectedExecution方法即可,例如讓被拒絕的任務(wù)在一個新的線程中執(zhí)行:
static class MyRejectedExecutionHandler implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
new Thread(r,"新線程"+new Random().nextInt(10)).start();
}
}
Java自帶的四種線程池
如果你不想自己寫一個線程池,Java通過Executors這個類提供了四種線程池,這四種線程池都是直接或間接配置ThreadPoolExecutor的參數(shù)實(shí)現(xiàn)的。
- 1.CachedThreadPool:可緩存線程池
/**
* 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>());
}
/**
* Creates a thread pool that creates new threads as needed, but
* will reuse previously constructed threads when they are
* available, and uses the provided
* ThreadFactory to create new threads when needed.
* @param threadFactory the factory to use when creating new threads
* @return the newly created thread pool
* @throws NullPointerException if threadFactory is null
*/
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
根據(jù)源碼可以看出:
1.這種線程池內(nèi)部沒有核心線程,線程的數(shù)量是有沒限制的。
2.在創(chuàng)建任務(wù)時,若有空閑的線程時則復(fù)用空閑的線程,若沒有則新建線程。
3.沒有工作的線程(閑置狀態(tài))在超過了60S還不做事,就會銷毀。
- 2.FixedThreadPool:定長線程池
/**
* Creates a thread pool that reuses a fixed number of threads
* operating off a shared unbounded queue. At any point, at most
* {@code nThreads} threads will be active processing tasks.
* If additional tasks are submitted when all threads are active,
* they will wait in the queue until a thread is available.
* If any thread terminates due to a failure during execution
* prior to shutdown, a new one will take its place if needed to
* execute subsequent tasks. The threads in the pool will exist
* until it is explicitly {@link ExecutorService#shutdown shutdown}.
*
* @param nThreads the number of threads in the pool
* @return the newly created thread pool
* @throws IllegalArgumentException if {@code nThreads <= 0}
*/
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
/**
* Creates a thread pool that reuses a fixed number of threads
* operating off a shared unbounded queue, using the provided
* ThreadFactory to create new threads when needed. At any point,
* at most {@code nThreads} threads will be active processing
* tasks. If additional tasks are submitted when all threads are
* active, they will wait in the queue until a thread is
* available. If any thread terminates due to a failure during
* execution prior to shutdown, a new one will take its place if
* needed to execute subsequent tasks. The threads in the pool will
* exist until it is explicitly {@link ExecutorService#shutdown
* shutdown}.
*
* @param nThreads the number of threads in the pool
* @param threadFactory the factory to use when creating new threads
* @return the newly created thread pool
* @throws NullPointerException if threadFactory is null
* @throws IllegalArgumentException if {@code nThreads <= 0}
*/
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
根據(jù)源碼可以看出:
1.該線程池的最大線程數(shù)等于核心線程數(shù),所以在默認(rèn)情況下,該線程池的線程不會因?yàn)殚e置狀態(tài)超時而被銷毀。
2.如果當(dāng)前線程數(shù)小于核心線程數(shù),并且也有閑置線程的時候提交了任務(wù),這時也不會去復(fù)用之前的閑置線程,會創(chuàng)建新的線程去執(zhí)行任務(wù)。如果當(dāng)前執(zhí)行任務(wù)數(shù)大于了核心線程數(shù),大于的部分就會進(jìn)入隊(duì)列等待。等著有閑置的線程來執(zhí)行這個任務(wù)。
- SingleThreadPool單線程線程池
/**
* 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>()));
}
/**
* Creates an Executor that uses a single worker thread operating
* off an unbounded queue, and uses the provided ThreadFactory to
* create a new thread when needed. Unlike the otherwise
* equivalent {@code newFixedThreadPool(1, threadFactory)} the
* returned executor is guaranteed not to be reconfigurable to use
* additional threads.
*
* @param threadFactory the factory to use when creating new
* threads
*
* @return the newly created single-threaded Executor
* @throws NullPointerException if threadFactory is null
*/
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory));
}
根據(jù)源碼可以看出:
1.有且僅有一個工作線程執(zhí)行任務(wù)
2.所有任務(wù)按照指定順序執(zhí)行,即遵循隊(duì)列的入隊(duì)出隊(duì)規(guī)則
- ScheduledThreadPool延期周期執(zhí)行線程池
/**
* Creates a thread pool that can schedule commands to run after a
* given delay, or to execute periodically.
* @param corePoolSize the number of threads to keep in the pool,
* even if they are idle
* @return a newly created scheduled thread pool
* @throws IllegalArgumentException if {@code corePoolSize < 0}
*/
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
/**
* Creates a thread pool that can schedule commands to run after a
* given delay, or to execute periodically.
* @param corePoolSize the number of threads to keep in the pool,
* even if they are idle
* @param threadFactory the factory to use when the executor
* creates a new thread
* @return a newly created scheduled thread pool
* @throws IllegalArgumentException if {@code corePoolSize < 0}
* @throws NullPointerException if threadFactory is null
*/
public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
根據(jù)源碼可以看出:
DEFAULT_KEEPALIVE_MILLIS就是默認(rèn)10L,這里就是10秒。這個線程池有點(diǎn)像是吧CachedThreadPool和FixedThreadPool 結(jié)合了一下。
不僅設(shè)置了核心線程數(shù),最大線程數(shù)也是Integer.MAX_VALUE。
這個線程池是上述4個中為唯一個有延遲執(zhí)行和周期執(zhí)行任務(wù)的線程池。
線程池的執(zhí)行流程
- 新任務(wù)進(jìn)來先看是否有可用核心線程,如果有,則使用核心線程處理此任務(wù)
- 如果核心線程數(shù)已滿,則添加到任務(wù)隊(duì)列等待處理
- 如果任務(wù)隊(duì)列已滿,且核心線程數(shù)已滿,則使用非核心線程處理任務(wù)
- 如果隊(duì)列已滿,核心線程和非核心線程都已滿,則執(zhí)行拒絕策略
線程池的關(guān)閉
ThreadPoolExecutor提供了兩個方法,用于線程池的關(guān)閉,分別是shutdown()和shutdownNow(),其中:
- shutdown():不會立即終止線程池,而是要等所有任務(wù)緩存隊(duì)列中的任務(wù)都執(zhí)行完后才終止,但再也不會接受新的任務(wù)
- shutdownNow():立即終止線程池,并嘗試打斷正在執(zhí)行的任務(wù),并且清空任務(wù)緩存隊(duì)列,返回尚未執(zhí)行的任務(wù)
如何選擇線程池數(shù)量
線程池的大小決定著系統(tǒng)的性能,過大或者過小的線程池數(shù)量都無法發(fā)揮最優(yōu)的系統(tǒng)性能。
當(dāng)然線程池的大小也不需要做的太過于精確,只需要避免過大和過小的情況。一般來說,確定線程池的大小需要考慮CPU的數(shù)量,內(nèi)存大小,任務(wù)是計算密集型還是IO密集型等因素。
NCPU = CPU的數(shù)量
UCPU = 期望對CPU的使用率 0 ≤ UCPU ≤ 1
W/C = 等待時間與計算時間的比率
如果希望處理器達(dá)到理想的使用率,那么線程池的最優(yōu)大小為:
線程池大小=NCPU * UCPU(1+W/C)
在Java中使用int ncpus = Runtime.getRuntime().availableProcessors();可以獲取CPU的數(shù)量。
線程池工廠
Executors的線程池如果不指定線程工廠會使用Executors中的DefaultThreadFactory
默認(rèn)線程池工廠創(chuàng)建的線程都是非守護(hù)線程。
使用自定義的線程工廠可以做很多事情,比如可以跟蹤線程池在何時創(chuàng)建了多少線程,也可以自定義線程名稱和優(yōu)先級。如果將
新建的線程都設(shè)置成守護(hù)線程,當(dāng)主線程退出后,將會強(qiáng)制銷毀線程池。