utils包提供開了 ExecutorService 線程池的實(shí)現(xiàn)义矛,主要目的是為了重復(fù)利用線程,提高系統(tǒng)效率。
Thread是一個(gè)重量級(jí)的資源俐银,創(chuàng)建、啟動(dòng)以及銷毀都是比較耗費(fèi)系統(tǒng)資源的端仰,因此使用線程池來管理線程是一個(gè)非常重要的編程習(xí)慣捶惜。
1、Thread
new Thread(new Runnable() {
@Override
public void run() {
}
}).start();
直接使用 Thread 的弊端如下:
- 每次new Thread新建對(duì)象性能差荔烧。
- 線程缺乏統(tǒng)一管理吱七,可能無限制新建線程,相互之間競(jìng)爭(zhēng)鹤竭,及可能占用過多系統(tǒng)資源導(dǎo)致死機(jī)或oom踊餐。
- 缺乏更多功能,如定時(shí)執(zhí)行臀稚、定期執(zhí)行吝岭、線程中斷。
2吧寺、線程池(ExecutorService窜管、ThreadPool)
(1)newCachedThreadPool
創(chuàng)建一個(gè)可緩存線程池,如果線程池長(zhǎng)度超過處理需要稚机,可靈活回收空閑線程幕帆,若無可回收,則新建線程
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() {
@Override
public void run() {
System.out.println(index);
}
});
}
cachedThreadPool.shutdown();
線程池為無限大赖条,當(dāng)執(zhí)行第二個(gè)任務(wù)時(shí)第一個(gè)任務(wù)已經(jīng)完成失乾,會(huì)復(fù)用執(zhí)行第一個(gè)任務(wù)的線程常熙,而不用每次新建線程。
(2)newFixedThreadPool
創(chuàng)建一個(gè)定長(zhǎng)線程池仗扬,可控制線程最大并發(fā)數(shù)症概,超出的線程會(huì)在隊(duì)列中等待
ExecutorService cachedThreadPool = Executors.newFixedThreadPool(5);
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() {
@Override
public void run() {
System.out.println(index);
}
});
}
cachedThreadPool.shutdown();
這里支持的最大線程數(shù)是5, 也可以根據(jù)系統(tǒng)而定早芭,獲取系統(tǒng)可被利用的進(jìn)程數(shù)
Runtime.getRuntime().availableProcessors()
(3)newScheduledThreadPool
創(chuàng)建一個(gè)定長(zhǎng)線程池彼城,支持定時(shí)及周期性任務(wù)執(zhí)行。
定義線程池退个,最大線程數(shù)是5
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
延遲執(zhí)行:
scheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
System.out.println("delay");
}
}, 3, TimeUnit.SECONDS);
延遲1秒募壕,并每隔3秒定期執(zhí)行
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("delay 1 seconds, and excute every 3 seconds");
}
}, 1, 3, TimeUnit.SECONDS);
關(guān)于延遲執(zhí)行和周期性執(zhí)行我們還會(huì)想到Timer
Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
}
};
timer.schedule(timerTask, 1000, 3000);
(4)newSingleThreadExecutor
創(chuàng)建一個(gè)單線程化的線程池,它只會(huì)用唯一的工作線程來執(zhí)行任務(wù)语盈,保證所有任務(wù)按照指定順序(FIFO, LIFO, 優(yōu)先級(jí))執(zhí)行舱馅。
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
Java提供的四種線程池的優(yōu)點(diǎn)
- 重用存在的線程,減少對(duì)象創(chuàng)建刀荒、消亡的開銷代嗤,性能佳。
- 可有效控制最大并發(fā)線程數(shù)缠借,提高系統(tǒng)資源的使用率干毅,同時(shí)避免過多資源競(jìng)爭(zhēng),避免堵塞泼返。
- 提供定時(shí)執(zhí)行硝逢、定期執(zhí)行、單線程绅喉、并發(fā)數(shù)控制等功能渠鸽。
(5)自定義線程池
如果我們不想使用以上4種線程池,可以自定義一個(gè)線程池:
/**
* 線程池
*/
public class DefaultPoolExecutor {
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
@Override
public Thread newThread(Runnable runnable) {
// 線程
return new Thread(runnable, "ThreadName #" + mCount.getAndIncrement());
}
};
// 可用處理器的Java虛擬機(jī)的數(shù)量
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// 最大線程數(shù)(最佳線程數(shù) = CPU_COUNT + 1)
private static final int MAX_CORE_POOL_SIZE = CPU_COUNT + 1;
//空閑時(shí)間達(dá)到 30s 時(shí)柴罐,回收空閑線程(每隔30s回收一次)
private static final long THREAD_TIMEOUT = 30L;
/**
* 新建一個(gè)線程池
* 每個(gè)線程都會(huì)消耗大概1M的內(nèi)存徽缚,使用線程池管理和復(fù)用線程
*
* @param corePoolSize 線程池大小
* @return
*/
public static ThreadPoolExecutor newDefaultPoolExecutor(int corePoolSize) {
if (corePoolSize == 0) {
return null;
}
corePoolSize = Math.min(corePoolSize, MAX_CORE_POOL_SIZE);
int maximumPoolSize = corePoolSize;
// corePoolSize: 當(dāng)線程池小于corePoolSize時(shí),新提交任務(wù)將創(chuàng)建一個(gè)新線程執(zhí)行任務(wù)革屠,即使此時(shí)線程池中存在空閑線程
// 當(dāng)線程池達(dá)到corePoolSize時(shí)凿试,新提交任務(wù)將被放入workQueue中,等待線程池中任務(wù)調(diào)度執(zhí)行
// 當(dāng)workQueue已滿屠阻,且maximumPoolSize>corePoolSize時(shí)红省,新提交任務(wù)會(huì)創(chuàng)建新線程執(zhí)行任務(wù)
// 當(dāng)提交任務(wù)數(shù)超過maximumPoolSize時(shí),新提交任務(wù)由RejectedExecutionHandler處理
// 當(dāng)線程池中超過corePoolSize線程国觉,空閑時(shí)間達(dá)到keepAliveTime時(shí)吧恃,關(guān)閉空閑線程
// 當(dāng)設(shè)置allowCoreThreadTimeOut(true)時(shí),線程池中線程空閑時(shí)間達(dá)到keepAliveTime也將關(guān)閉
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, THREAD_TIMEOUT,
TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(64), sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
return threadPoolExecutor;
}
}
擴(kuò)充:
除了execute可以執(zhí)行線程池中的線程之外麻诀,submit也是可以的
submit的效果和execute是一樣的痕寓,只是execute沒有返回值傲醉,而submit有返回值。
(1)Future<?> submit(Runnable task)
Future future1 = singleThreadExecutor.submit(new Runnable() {
@Override
public void run() {
}
});
(2)<T> Future<T> submit(Runnable task, T result)
Future<String> future = singleThreadExecutor.submit(new Runnable() {
@Override
public void run() {
}
}, "A");
(3)<T> Future<T> submit(Callable<T> task);
Callable callable = new Callable<String>() {
@Override
public String call() throws Exception {
return "A";
}
};
Future<String> future = singleThreadExecutor.submit(callable);
如果Future中有值的話可以通過以下代碼獲取
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
Future的其余操作如圖
[本章完...]