線程池的優(yōu)點(diǎn)
①降低系統(tǒng)資源消耗,通過重用已存在的線程碳却,降低線程創(chuàng)建和銷毀造成的消耗;
②提高系統(tǒng)響應(yīng)速度笑旺,當(dāng)有任務(wù)到達(dá)時(shí)昼浦,無需等待新線程的創(chuàng)建便能立即執(zhí)行;
③方便線程并發(fā)數(shù)的管控筒主,線程若是無限制的創(chuàng)建关噪,不僅會額外消耗大量系統(tǒng)資源鸟蟹,更是占用過多資源而阻塞系統(tǒng)或oom等狀況,從而降低系統(tǒng)的穩(wěn)定性使兔。線程池能有效管控線程建钥,統(tǒng)一分配、調(diào)優(yōu)火诸,提供資源使用率锦针;
④更強(qiáng)大的功能,線程池提供了定時(shí)置蜀、定期以及可控線程數(shù)等功能的線程池奈搜,使用方便簡單。
參考
線程池的創(chuàng)建
使用ThreadPoolExecutor創(chuàng)建
ExecutorService service = new ThreadPoolExecutor(....);
下面我們就來看一下ThreadPoolExecutor中的一個(gè)構(gòu)造方法盯荤。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
ThreadPollExcutor參數(shù)含義
**1. corePoolSize **
線程池中的核心線程馋吗,一般情況下,核心線程一直存活在線程池中秋秤。
2. maximumPoolSize
線程池中的最大線程數(shù)宏粤。當(dāng)活動線程數(shù)大于這個(gè)值,后續(xù)的新任務(wù)將阻塞灼卢,包括核心線程和非核心線程绍哎。
3. keepAliveTime
非核心線程限制的超時(shí)時(shí)間,當(dāng)非核心線程閑置時(shí)間超過這個(gè)值鞋真,非核心線程就會被回收崇堰。
4. unit
用于指定keepAliveTime參數(shù)的時(shí)間單位。他是一個(gè)枚舉涩咖,可以使用的單位有天(TimeUnit.DAYS)海诲,小時(shí)(TimeUnit.HOURS),分鐘(TimeUnit.MINUTES)檩互,毫秒(TimeUnit.MILLISECONDS)特幔,微秒(TimeUnit.MICROSECONDS, 千分之一毫秒)和毫微秒(TimeUnit.NANOSECONDS, 千分之一微秒);
** 5. workQueue**
線程池中保存等待任務(wù)的阻塞隊(duì)列。
阻塞隊(duì)列 | 說明 |
---|---|
ArrayBlockingQueue | 基于數(shù)組實(shí)現(xiàn)的有界的阻塞隊(duì)列,該隊(duì)列按照FIFO(先進(jìn)先出)原則對隊(duì)列中的元素進(jìn)行排序闸昨。 |
LinkedBlockingQueue | 基于鏈表實(shí)現(xiàn)的阻塞隊(duì)列蚯斯,該隊(duì)列按照FIFO(先進(jìn)先出)原則對隊(duì)列中的元素進(jìn)行排序。 |
SynchronousQueue | 內(nèi)部沒有任何容量的阻塞隊(duì)列饵较。在它內(nèi)部沒有任何的緩存空間溉跃。對于SynchronousQueue中的數(shù)據(jù)元素只有當(dāng)我們試著取走的時(shí)候才可能存在。 |
PriorityBlockingQueue | 具有優(yōu)先級的無限阻塞隊(duì)列告抄。 |
我們還能夠通過實(shí)現(xiàn)BlockingQueue接口來自定義我們所需要的阻塞隊(duì)列。
6. ThreadFactory
線程工廠嵌牺,為線程池提供新線程的創(chuàng)建打洼。ThreadFactory是一個(gè)接口龄糊,里面只有一個(gè)newThread方法。 默認(rèn)為DefaultThreadFactory類募疮。
對于ThreadPoolExecutor有多個(gè)構(gòu)造方法炫惩,對于上面的構(gòu)造方法中的其他參數(shù)都采用默認(rèn)值“⑴ǎ可以通過execute和submit兩種方式來向線程池提交一個(gè)任務(wù)他嚷。 execute 當(dāng)我們使用execute來提交任務(wù)時(shí),由于execute方法沒有返回值芭毙,所以說我們也就無法判定任務(wù)是否被線程池執(zhí)行成功筋蓖。
submit
當(dāng)我們使用submit來提交任務(wù)時(shí),它會返回一個(gè)future,我們就可以通過這個(gè)future來判斷任務(wù)是否執(zhí)行成功,還可以通過future的get方法來獲取返回值退敦。如果子線程任務(wù)沒有完成粘咖,get方法會阻塞住直到任務(wù)完成,而使用get(long timeout, TimeUnit unit)方法則會阻塞一段時(shí)間后立即返回侈百,這時(shí)候有可能任務(wù)并沒有執(zhí)行完瓮下。
線程池關(guān)閉
調(diào)用線程池的shutdown()或shutdownNow()方法來關(guān)閉線程池
shutdown原理:將線程池狀態(tài)設(shè)置成SHUTDOWN狀態(tài),然后中斷所有沒有正在執(zhí)行任務(wù)的線程钝域。
shutdownNow原理:將線程池的狀態(tài)設(shè)置成STOP狀態(tài)讽坏,然后中斷所有任務(wù)(包括正在執(zhí)行的)的線程,并返回等待執(zhí)行任務(wù)的列表例证。
中斷采用interrupt方法路呜,所以無法響應(yīng)中斷的任務(wù)可能永遠(yuǎn)無法終止。 但調(diào)用上述的兩個(gè)關(guān)閉之一战虏,isShutdown()方法返回值為true拣宰,當(dāng)所有任務(wù)都已關(guān)閉,表示線程池關(guān)閉完成烦感,則isTerminated()方法返回值為true巡社。當(dāng)需要立刻中斷所有的線程,不一定需要執(zhí)行完任務(wù)手趣,可直接調(diào)用shutdownNow()方法晌该。
一個(gè)線程不應(yīng)該由其他線程來強(qiáng)制中斷或停止,而是應(yīng)該由線程自己自行停止绿渣。所以朝群,Thread.stop, Thread.suspend, Thread.resume 都已經(jīng)被廢棄了。而 Thread.interrupt 的作用其實(shí)也不是中斷線程中符,而是「通知線程應(yīng)該中斷了」姜胖,具體到底中斷還是繼續(xù)運(yùn)行,應(yīng)該由被通知的線程自己處理淀散。
Java四種線程池
Java中四種具有不同功能常見的線程池右莱。他們都是直接或者間接配置ThreadPoolExecutor來實(shí)現(xiàn)他們各自的功能蚜锨。這四種線程池分別是newFixedThreadPool,newCachedThreadPool,newScheduledThreadPool和newSingleThreadExecutor。這四個(gè)線程池可以通過Executors類獲取慢蜓。
1. newFixedThreadPool
該線程池是線程數(shù)量固定的線程池亚再。NewFixedThreadPool只有核心線程,而且這些線程不會被銷毀晨抡。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
2. newCachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
該線程的核心線程數(shù)為0氛悬,最大線程數(shù)量為無限。
3. newScheduledThreadPool
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
該線程的核心線程數(shù)是固定的耘柱,非核心線程數(shù)是無限的如捅,當(dāng)非核心線程數(shù)限制時(shí)間超過了,就會被回收帆谍。
該線程可創(chuàng)建延時(shí)或者定時(shí)線程任務(wù)伪朽。
ScheduledExecutorService service = Executors.newScheduledThreadPool(4);
service.schedule(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName()+"延遲三秒執(zhí)行");
}
}, 3, TimeUnit.SECONDS);
service.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName()+"延遲三秒后每隔2秒執(zhí)行");
}
}, 3, 2, TimeUnit.SECONDS);
4. newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
該線程池的核心線程和最大線程數(shù)都是1,表示這個(gè)線程的活動線程永遠(yuǎn)都只有一個(gè)汛蝙,且不會被回收烈涮。