Executors為Executor乘寒,ExecutorService,ScheduledExecutorService辩撑,ThreadFactory和Callable類提供了一些工具方法方面,類似于集合中的Collections類的功能。
生成線程池采用了工具類Executors的靜態(tài)方法岩榆,以下是幾種常見的線程池错负。
1>newCachedThreadPool :該線程池比較適合沒有固定大小并且比較快速就能完成的小任務(wù),它將為每個任務(wù)創(chuàng)建一個線程勇边。那這樣子它與直接創(chuàng)建線程對象(new Thread())有什么區(qū)別呢犹撒?看到它的第三個參數(shù)60L和第四個參數(shù)TimeUnit.SECONDS了嗎?好處就在于60秒內(nèi)能夠重用已創(chuàng)建的線程粒褒。
CachedThreadPool:無界線程池识颊,可以進(jìn)行自動線程回收。
下面是Executors中的newCachedThreadPool()的源代碼:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
}
如果線程池的大小超過了處理任務(wù)所需要的線程,那么就會回收部分空閑(60秒不執(zhí)行任務(wù))的線程祥款,當(dāng)任務(wù)數(shù)增加時清笨,此線程池又可以智能的添加新線程來處理任務(wù)。此線程池不會對線程池大小做限制刃跛,線程池大小完全依賴于操作系統(tǒng)(或者說JVM)能夠創(chuàng)建的最大線程大小抠艾。SynchronousQueue是一個是緩沖區(qū)為1的阻塞隊列。
示例代碼如下:
packagetest;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
public class ThreadPoolExecutorTest{
public static void main(String[]args){
ExecutorService cachedThreadPool= Executors.newCachedThreadPool();
for(int i=0;i<10;i++){
final int index=i;
try{
Thread.sleep(index*1000);
}catch(InterruptedException e){
e.printStackTrace();
}
cachedThreadPool.execute(new Runnable(){
public void run(){
System.out.println(index);
}
});
}
}
}
//線程池為無限大桨昙,當(dāng)執(zhí)行第二個任務(wù)時第一個任務(wù)已經(jīng)完成检号,會復(fù)用執(zhí)行第一個任務(wù)的線程,而不用每次新建線程蛙酪。
2> newFixedThreadPool使用的Thread對象的數(shù)量是有限的,如果提交的任務(wù)數(shù)量大于限制的最大線程數(shù)齐苛,那么這些任務(wù)講排隊,然后當(dāng)有一個線程的任務(wù)結(jié)束之后桂塞,將會根據(jù)調(diào)度策略繼續(xù)等待執(zhí)行下一個任務(wù)脸狸。
FixedThreadPool:只有核心線程的線程池,大小固定 (其緩沖隊列是無界的) 。
下面是Executors中的newFixedThreadPool()的源代碼:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}
創(chuàng)建固定大小的線程池藐俺。每次提交一個任務(wù)就創(chuàng)建一個線程炊甲,直到線程達(dá)到線程池的最大大小。線程池的大小一旦達(dá)到最大值就會保持不變欲芹,如果某個線程因為執(zhí)行異常而結(jié)束卿啡,那么線程池會補(bǔ)充一個新線程。
示例代碼如下:
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
//因為線程池大小為3菱父,每個任務(wù)輸出index后sleep 2秒颈娜,所以每兩秒打印3個數(shù)字。
//定長線程池的大小最好根據(jù)[系統(tǒng)](http://www.2cto.com/os/)資源進(jìn)行設(shè)置浙宜。如Runtime.getRuntime().availableProcessors()
3>newSingleThreadExecutor就是線程數(shù)量為1的FixedThreadPool,如果提交了多個任務(wù)官辽,那么這些任務(wù)將會排隊,每個任務(wù)都會在下一個任務(wù)開始之前運(yùn)行結(jié)束粟瞬,所有的任務(wù)將會使用相同的線程同仆。
SingleThreadExecutor:單個后臺線程 (其緩沖隊列是無界的)
下面是Executors中的newSingleThreadExecutor()的源代碼:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
}
創(chuàng)建一個單線程的線程池。這個線程池只有一個核心線程在工作裙品,也就是相當(dāng)于單線程串行執(zhí)行所有任務(wù)俗批。如果這個唯一的線程因為異常結(jié)束,那么會有一個新的線程來替代它市怎。此線程池保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行岁忘。
示例代碼如下:
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
//結(jié)果依次輸出,相當(dāng)于順序執(zhí)行各個任務(wù)区匠。
4>newScheduledThreadPool創(chuàng)建一個固定長度的線程池干像,而且以延遲或定時的方式來執(zhí)行任務(wù)。
ScheduledThreadPool:核心線程池固定,大小無限的線程池麻汰。此線程池支持定時以及周期性執(zhí)行任務(wù)的需求速客。
public static ExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPool(corePoolSize,
Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
創(chuàng)建一個周期性執(zhí)行任務(wù)的線程池。如果閑置,非核心線程池會在DEFAULT_KEEPALIVEMILLIS時間內(nèi)回收什乙。
示例代碼如下:
package test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
public void run() {
System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);
}
}
//表示延遲3秒執(zhí)行。
定期執(zhí)行示例代碼如下:
package test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println("delay 1 seconds, and excute every 3 seconds");
}
}, 1, 3, TimeUnit.SECONDS);
}
}
//表示延遲1秒后每3秒執(zhí)行一次已球。
通過如上配置的線程池的創(chuàng)建方法源代碼臣镣,我們可以發(fā)現(xiàn):
1、 除了CachedThreadPool使用的是直接提交策略的緩沖隊列以外智亮,其余兩個用的采用的都是無界緩沖隊列忆某,也就說,F(xiàn)ixedThreadPool和SingleThreadExecutor創(chuàng)建的線程數(shù)量就不會超過 corePoolSize阔蛉。
2弃舒、我們可以再來看看三個線程池采用的ThreadPoolExecutor構(gòu)造方法都是同一個,使用的都是默認(rèn)的ThreadFactory和handler:
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
也就說三個線程池創(chuàng)建的線程對象都是同組状原,優(yōu)先權(quán)等級為正常的Thread.NORM_PRIORITY(5)的非守護(hù)線程聋呢,使用的被拒絕任務(wù)處理方式是直接拋出異常的AbortPolicy策略。
線程池最常用的提交任務(wù)的方法有兩種:
execute:
ExecutorService.execute(Runnable runable)颠区;
submit:
FutureTask task = ExecutorService.submit(Runnable runnable);
FutureTask<T> task = ExecutorService.submit(Runnable runnable,T Result);
FutureTask<T> task = ExecutorService.submit(Callable<T> callable);
submit(Callable callable)的實現(xiàn)削锰,submit(Runnable runnable)同理。
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
FutureTask<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
可以看出submit開啟的是有返回結(jié)果的任務(wù)毕莱,會返回一個FutureTask對象器贩,這樣就能通過get()方法得到結(jié)果。submit最終調(diào)用的也是execute(Runnable runable)朋截,submit只是將Callable對象或Runnable封裝成一個FutureTask對象蛹稍,因為FutureTask是個Runnable,所以可以在execute中執(zhí)行部服。關(guān)于Callable對象和Runnable怎么封裝成FutureTask對象唆姐,見Callable和Future、FutureTask的使用廓八。
參考來自http://blog.csdn.net/zhoufenqin/article/details/51012666
參考來自http://blog.csdn.net/he90227/article/details/52576452
參考來自http://www.2cto.com/kf/201606/517766.html