Android開(kāi)發(fā)ThreadPoolExecutor與自定義線程池詳解
概述
1、ThreadPoolExecutor作為java.util.concurrent包對(duì)外提供基礎(chǔ)實(shí)現(xiàn),以?xún)?nèi)部線程池的形式對(duì)外提供管理任務(wù)執(zhí)行,線程調(diào)度,線程池管理等等服務(wù);
2、Executors方法提供的線程服務(wù),都是通過(guò)參數(shù)設(shè)置來(lái)實(shí)現(xiàn)不同的線程池機(jī)制。
3、先來(lái)了解其線程池管理的機(jī)制,有助于正確使用,避免錯(cuò)誤使用導(dǎo)致嚴(yán)重故障。同時(shí)可以根據(jù)自己的需求實(shí)現(xiàn)自己的線程池
ThreadPoolExecutor 類(lèi)
構(gòu)造方法
public ThreadPoolExecutor( int corePoolSize, //核心線程數(shù)量:如果當(dāng)前運(yùn)行的線程數(shù)量沒(méi)有達(dá)到 corePoolSize,則新建一個(gè)線程,否則加入到任務(wù)隊(duì)列中 int maximumPoolSize, //最大線程數(shù):當(dāng)前系統(tǒng)最多存在的線程數(shù) long keepAliveTime, //最大空閑時(shí)間:線程空閑的最大時(shí)間,超出時(shí)間該線程會(huì)銷(xiāo)毀;設(shè)置allowCodeThreadTimeOut(true/false),可控制核心線程是否銷(xiāo)毀,默認(rèn)false 表示允許核心線程即使超過(guò)最大線程時(shí)間也不會(huì)銷(xiāo)毀 TimeUnit unit, //時(shí)間單位: 線程空閑的最大時(shí)間的單位 BlockingQueue<Runnable> workQueue, //任務(wù)隊(duì)列: 核心線程數(shù)量滿(mǎn)了之后,提交的任務(wù)加入到隊(duì)列中,等待核心線程數(shù)減少后再去創(chuàng)建線程;當(dāng)任務(wù)隊(duì)列已滿(mǎn),但沒(méi)有達(dá)到最大線程數(shù)時(shí),則新建非核心線程 ThreadFactory threadFactory, //線程工廠: 自定義線程的創(chuàng)建 RejectedExecutionHandler handler //飽和處理機(jī)制:當(dāng)任務(wù)隊(duì)列已滿(mǎn)且達(dá)到最大線程數(shù)時(shí),采取的措施 )
線程池原理
線程池底層使用**堵塞式隊(duì)列 BlockingQueue **。
隊(duì)列遵從:先進(jìn)先出,后進(jìn)后出原則。 阻塞隊(duì)列(BlockingQueue)和非阻塞隊(duì)列(ConcurrentLinkedQueue )區(qū)別:
無(wú)界和有界隊(duì)列:
ConcurrentLinkedQueue 是無(wú)界隊(duì)列,不用設(shè)置長(zhǎng)度,可以隨便存放值(其實(shí)是jdk偽造的,最大長(zhǎng)度是Integer的最大值) BlockingQueue 是有界隊(duì)列,需要設(shè)置長(zhǎng)度。 注意:如果BlockingQueue 不設(shè)置等待時(shí)間就是非阻塞隊(duì)列
存入:
非阻塞隊(duì)列:如果存放超出了隊(duì)列總數(shù),添加不進(jìn)去,就會(huì)丟失。 阻塞隊(duì)列:如果存放超出了隊(duì)列總數(shù),進(jìn)行等待,直到有隊(duì)列出列,或者超時(shí)設(shè)置的等待時(shí)間)
獲?。?/h4>
非阻塞隊(duì)列:如果為空時(shí),返回空。 阻塞隊(duì)列:如果為空時(shí),進(jìn)行等待,直到有新的隊(duì)列入列,或者超過(guò)設(shè)置的等待時(shí)間
創(chuàng)建線程池的構(gòu)造方法
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue)
- ThreadPoolExecutor
- 參數(shù)說(shuō)明
- 核心線程大小(corePoolSize)
- 最大線程大小(maximumPoolSize)
- 終止時(shí)間(keepAliveTime)
- Unit 超時(shí)時(shí)間
- workQueue 線程容器
自定義線程池
1、編寫(xiě)任務(wù)類(lèi)
public class MyTask implements Runnable{
//任務(wù)id
private int id;
public MyTask(int id){
this.id=id;
}
@Override
public void run() {
String name=Thread.currentThread().getName();
System.out.println("線程:"+name+"-->即將執(zhí)行任務(wù)"+id);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("線程:"+name+"執(zhí)行完成"+id);
}
@Override
public String toString() {
return "MyTask{" +
"id=" + id +
'}';
}
}
2、編寫(xiě)線程類(lèi),用于執(zhí)行任務(wù)
public class MyThread extends Thread{
private List<Runnable> tasks;
public MyThread(String name, List<Runnable> tasks){
super(name);
this.tasks=tasks;
}
@Override
public void run() {
while (tasks.size() > 0){
Runnable r= tasks.remove(0);
r.run();
}
}
}
3、編寫(xiě)線程池類(lèi),用于管理線程的執(zhí)行
public class MyThreadPool {
private List<Runnable> tasks = Collections.synchronizedList(new LinkedList<>());
/**
* 當(dāng)前線程數(shù)
*/
private int num;
/**
* 核心線程數(shù)
*/
private int corePoolSize;
/**
* 最大線程數(shù)
*/
private int maxSize;
/**
* 任務(wù)隊(duì)列數(shù)
*/
private int workSize;
public MyThreadPool(int corePoolSize, int maxSize, int workSize) {
this.corePoolSize = corePoolSize;
this.maxSize = maxSize;
this.workSize = workSize;
}
/**
* 提交任務(wù)
*/
public void submit(Runnable r){
if (tasks.size()>=workSize && tasks.size() > maxSize){
System.out.println("任務(wù):"+r+"被丟棄了");
}else{
tasks.add(r);
execTask(r);
}
}
public void execTask(Runnable r){
if (corePoolSize > num){
new MyThread("核心線程:"+num,tasks).start();
num++;
}else if(num < maxSize){
new MyThread("非核心線程:"+num,tasks).start();
num++;
}else{
System.out.println("任務(wù):"+r+"被緩存了");
}
}
}
4、測(cè)試
public class Demo {
public static void main(String[] args) {
MyThreadPool myThreadPool = new MyThreadPool(2, 4, 20);
for (int i =0;i< 300;i++){
MyTask myTask = new MyTask(i);
myThreadPool.submit(myTask);
}
}
}
以上就是Android開(kāi)發(fā)中ThreadPoolExecutor與自定義線程池;
文末
1、用ThreadPoolExecutor自定義線程池,看線程是的用途,如果任務(wù)量不大,可以用無(wú)界隊(duì)列,如果任務(wù)量非常大,要用有界隊(duì)列,防止OOM
2、如果任務(wù)量很大,還要求每個(gè)任務(wù)都處理成功,要對(duì)提交的任務(wù)進(jìn)行阻塞提交,重寫(xiě)拒絕機(jī)制,改為阻塞提交。保證不拋棄一個(gè)任務(wù)
3、最大線程數(shù)一般設(shè)為2N+1最好,N是CPU核數(shù)
4、核心線程數(shù),看應(yīng)用,如果是任務(wù),一天跑一次,設(shè)置為0,合適,因?yàn)榕芡昃屯5袅?,如果是常用線程池,看任務(wù)量,是保留一個(gè)核心還是幾個(gè)核心線程數(shù)
5、如果要獲取任務(wù)執(zhí)行結(jié)果,用CompletionService,但是注意,獲取任務(wù)的結(jié)果的要重新開(kāi)一個(gè)線程獲取,如果在主線程獲取,就要等任務(wù)都提交后才獲取,就會(huì)阻塞大量任務(wù)結(jié)果,隊(duì)列過(guò)大OOM,所以最好異步開(kāi)個(gè)線程獲取結(jié)果
以上就是Android開(kāi)發(fā)ThreadPoolExecutor與自定義線程池詳解的詳細(xì)內(nèi)容,更多關(guān)于Android ThreadPoolExecutor的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android 使用viewpager實(shí)現(xiàn)無(wú)限循環(huán)(定時(shí)+手動(dòng))
這篇文章主要介紹了Android 使用viewpager實(shí)現(xiàn)無(wú)限循環(huán)(定時(shí)+手動(dòng))的相關(guān)資料,需要的朋友可以參考下2015-11-11
發(fā)布?Android?library?到?Maven?解析
這篇文章主要介紹了發(fā)布?Android?library到Maven解析,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09
Android實(shí)現(xiàn)錄音監(jiān)聽(tīng)動(dòng)畫(huà)的示例代碼
在很多app種內(nèi)置了語(yǔ)音助手,也存在各種動(dòng)畫(huà),這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)錄音監(jiān)聽(tīng)動(dòng)畫(huà)的示例代碼,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12
TextView使用SpannableString設(shè)置復(fù)合文本 SpannableString實(shí)現(xiàn)TextView的鏈接
這篇文章主要為大家詳細(xì)介紹了如何利用SpannableString實(shí)現(xiàn)TextView的鏈接效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
Android實(shí)現(xiàn)類(lèi)似execel的表格 能回顯并能修改表格內(nèi)容的方法
今天小編就為大家分享一篇Android實(shí)現(xiàn)類(lèi)似execel的表格 能回顯并能修改表格內(nèi)容的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
android 調(diào)用系統(tǒng)的照相機(jī)和圖庫(kù)實(shí)例詳解
android手機(jī)有自帶的照相機(jī)和圖庫(kù),我們做的項(xiàng)目中有時(shí)用到上傳圖片到服務(wù)器,今天做了一個(gè)項(xiàng)目用到這個(gè)功能,所以把我的代碼記錄下來(lái)和大家分享,有需求的朋友可以參考下2012-12-12

