為什么用線程池,在Java中創(chuàng)建線程無(wú)非嗅剖。就是new Thread和實(shí)現(xiàn)Runable接口來(lái)創(chuàng)建線程根蟹,但是這種方法如果不去控制數(shù)量,一味的去new 的話是很損耗系統(tǒng)資源的拷肌。所以對(duì)于線程的優(yōu)化就有了線程池的出現(xiàn)到旦,它是可以把線程歸納到一個(gè)線程池統(tǒng)一管理和使用。
Java線程池的核心就是使用ThreadPoolExecutor類(lèi)看看它的構(gòu)造方法有什么參數(shù)
public ThreadPoolExecutor(int corePoolSize, 線程池中核心線程數(shù)量
int maximumPoolSize, 最大線程數(shù)量
long keepAliveTime, 保存活動(dòng)的時(shí)間,不過(guò)它起作用必須在一個(gè)前提下巨缘,就是當(dāng)線程池中的線程數(shù)量超過(guò)了corePoolSize時(shí)添忘,它表示多余的空閑線程的存活時(shí)間,
即:多余的空閑線程在超過(guò)keepAliveTime時(shí)間內(nèi)沒(méi)有任務(wù)的話則被銷(xiāo)毀若锁。而這個(gè)主要應(yīng)用在緩存線程池中
TimeUnit unit, 表示keepAliveTime的單位搁骑,常用的如:TimeUnit.SECONDS(秒)、TimeUnit.MILLISECONDS(毫秒)
BlockingQueue<Runnable> workQueue, 任務(wù)隊(duì)列又固,主要用來(lái)存儲(chǔ)已經(jīng)提交但未被執(zhí)行的任務(wù)仲器,不同的線程池采用的排隊(duì)策略不一樣
ThreadFactory threadFactory, 線程工廠,用來(lái)創(chuàng)建線程池中的線程仰冠,通常用默認(rèn)的即可
RejectedExecutionHandler handler 通常叫做拒絕策略乏冀,1、在線程池已經(jīng)關(guān)閉的情況下 2洋只、任務(wù)太多導(dǎo)致最大線程數(shù)和任務(wù)隊(duì)列已經(jīng)飽和辆沦,無(wú)法再接收新的任務(wù) 昼捍。在上面兩種情況下,只要滿足其中一種時(shí)肢扯,
在使用execute()來(lái)提交新的任務(wù)時(shí)將會(huì)拒絕妒茬,而默認(rèn)的拒絕策略是拋一個(gè)RejectedExecutionException異常
) {
Executors提供五種隊(duì)列對(duì)應(yīng)的Queue類(lèi)型
newFixedThreadPool()--LinkedBlockingQueue
newSingleThreadExecutor()--LinkedBlockingQueue
newCachedThreadPool()--SynchronousQueue
newScheduledThreadPool()--DelayedWorkQueue
newSingleThreadScheduledExecutor()--DelayedWorkQueue
LinkedBlockingQueue:無(wú)界的隊(duì)列
SynchronousQueue:直接提交的隊(duì)列
DelayedWorkQueue:等待隊(duì)列
五種隊(duì)列的作用
newFixedThreadPool() :
作用:該方法返回一個(gè)固定線程數(shù)量的線程池,該線程池中的線程數(shù)量始終不變蔚晨,即不會(huì)再創(chuàng)建新的線程郊闯,也不會(huì)銷(xiāo)毀已經(jīng)創(chuàng)建好的線程,自始自終都是那幾個(gè)固定的線程在工作蛛株,所以該線程池可以控制線程的最大并發(fā)數(shù)。
栗子:假如有一個(gè)新任務(wù)提交時(shí)育拨,線程池中如果有空閑的線程則立即使用空閑線程來(lái)處理任務(wù)谨履,如果沒(méi)有,則會(huì)把這個(gè)新任務(wù)存在一個(gè)任務(wù)隊(duì)列中熬丧,一旦有線程空閑了笋粟,則按FIFO方式處理任務(wù)隊(duì)列中的任務(wù)。newCachedThreadPool() :
作用:該方法返回一個(gè)可以根據(jù)實(shí)際情況調(diào)整線程池中線程的數(shù)量的線程池析蝴。即該線程池中的線程數(shù)量不確定害捕,是根據(jù)實(shí)際情況動(dòng)態(tài)調(diào)整的。
栗子:假如該線程池中的所有線程都正在工作闷畸,而此時(shí)有新任務(wù)提交尝盼,那么將會(huì)創(chuàng)建新的線程去處理該任務(wù),而此時(shí)假如之前有一些線程完成了任務(wù)佑菩,現(xiàn)在又有新任務(wù)提交盾沫,那么將不會(huì)創(chuàng)建新線程去處理,而是復(fù)用空閑的線程去處理新任務(wù)殿漠。那么此時(shí)有人有疑問(wèn)了赴精,那這樣來(lái)說(shuō)該線程池的線程豈不是會(huì)越集越多?其實(shí)并不會(huì)绞幌,因?yàn)榫€程池中的線程都有一個(gè)“保持活動(dòng)時(shí)間”的參數(shù)蕾哟,通過(guò)配置它,如果線程池中的空閑線程的空閑時(shí)間超過(guò)該“保存活動(dòng)時(shí)間”則立刻停止該線程莲蜘,而該線程池默認(rèn)的“保持活動(dòng)時(shí)間”為60s谭确。newSingleThreadExecutor() :
作用:該方法返回一個(gè)只有一個(gè)線程的線程池,即每次只能執(zhí)行一個(gè)線程任務(wù)菇夸,多余的任務(wù)會(huì)保存到一個(gè)任務(wù)隊(duì)列中琼富,等待這一個(gè)線程空閑,當(dāng)這個(gè)線程空閑了再按FIFO方式順序執(zhí)行任務(wù)隊(duì)列中的任務(wù)庄新。newScheduledThreadPool() :
作用:該方法返回一個(gè)可以控制線程池內(nèi)線程定時(shí)或周期性執(zhí)行某任務(wù)的線程池鞠眉。newSingleThreadScheduledExecutor() :
作用:該方法返回一個(gè)可以控制線程池內(nèi)線程定時(shí)或周期性執(zhí)行某任務(wù)的線程池薯鼠。只不過(guò)和上面的區(qū)別是該線程池大小為1,而上面的可以指定線程池的大小械蹋。
- 固定線程數(shù)出皇,如果超過(guò)了設(shè)置的數(shù)量,后續(xù)將不會(huì)繼續(xù)創(chuàng)建線程而是FIFO方式去處理隊(duì)列哗戈。
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int finalI = i;
executorService.execute(new Runnable() {
@Override
public void run() {
Log.i(TAG, Thread.currentThread().getName() + " 線程正在執(zhí)行第" + finalI + "個(gè)任務(wù)");
}
});
}
- 這個(gè)線程池就存在一個(gè)線程實(shí)例郊艘,不管有多少個(gè)都是走隊(duì)列處理
ExecutorService executorService1 = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int finalI = i;
executorService1.execute(new Runnable() {
@Override
public void run() {
Log.i(TAG, Thread.currentThread().getName() + " 線程正在執(zhí)行第" + finalI + "個(gè)任務(wù)");
}
});
}
- 這個(gè)會(huì)根據(jù)線池實(shí)際使用情況來(lái)創(chuàng)建線程,數(shù)量不能確定唯咬。
ExecutorService executorService2 = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int finalI = i;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService2.execute(new Runnable() {
@Override
public void run() {
Log.i(TAG, Thread.currentThread().getName() + " 線程正在執(zhí)行第" + finalI + "個(gè)任務(wù)");
try {
Thread.sleep(finalI *500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
- 可以定時(shí)的隊(duì)列
ScheduledExecutorService scheduledExecutorService = Executors
.newScheduledThreadPool(3);
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
Log.i(TAG, Thread.currentThread().getName());
}
}, 1, TimeUnit.MILLISECONDS);
ScheduledExecutorService scheduledExecutorService4 = Executors
.newScheduledThreadPool(3);
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
Log.i(TAG, Thread.currentThread().getName() );
}
},1,2, TimeUnit.MILLISECONDS);
ScheduledExecutorService scheduledExecutorService3 = Executors
.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
Log.i(TAG, Thread.currentThread().getName() );
}
},1,2,TimeUnit.SECONDS);
優(yōu)化線程池ThreadPoolExecutor
雖說(shuō)線程池極大改善了系統(tǒng)的性能纱注,不過(guò)創(chuàng)建線程池也是需要資源的,所以線程池內(nèi)線程數(shù)量的大小也會(huì)影響系統(tǒng)的性能胆胰,大了反而浪費(fèi)資源狞贱,小了反而影響系統(tǒng)的吞吐量,所以我們創(chuàng)建線程池需要把握一個(gè)度才能合理的發(fā)揮它的優(yōu)點(diǎn)蜀涨,通常來(lái)說(shuō)我們要考慮的因素有CPU的數(shù)量瞎嬉、內(nèi)存的大小、并發(fā)請(qǐng)求的數(shù)量等因素厚柳,按需調(diào)整氧枣。 通常核心線程數(shù)可以設(shè)為CPU數(shù)量+1,而最大線程數(shù)可以設(shè)為CPU的數(shù)量*2+1别垮。獲取CPU數(shù)量的方法為:
Runtime.getRuntime().availableProcessors();
shutdown()和shutdownNow()的區(qū)別
關(guān)于線程池的停止便监,ExecutorService為我們提供了兩個(gè)方法:shutdown和shutdownNow,這兩個(gè)方法各有不同碳想,可以根據(jù)實(shí)際需求方便的運(yùn)用茬贵,如下:
1.shutdown()方法在終止前允許執(zhí)行以前提交的任務(wù)。
2.shutdownNow()方法則是阻止正在任務(wù)隊(duì)列中等待任務(wù)的啟動(dòng)并試圖停止當(dāng)前正在執(zhí)行的任務(wù)移袍。