當前位置:首頁 » 安卓系統 » android線程池管理

android線程池管理

發布時間: 2022-09-15 04:02:57

❶ android中怎麼用線程池

一般是按照CPU的核數來定義,例如是4核的,一般一個fixed線程池定義為4個線程左右。

❷ android 線程池有什麼用

//在Android中實現線程池,首先需要實現一個線程工廠(ThreadFactory)的子類,具體實現方式如下所示(PriorityThreadFactory.java):
import android.os.Process;
/**
* A thread factory that create threads with a given thread priority
* @author jony
* @version 1.0
*/
public class PriorityThreadFactory implements ThreadFactory{
private final String mName;
private final int mPriority;
private final AtomicInteger mNumber = new AtomicInteger();

public PriorityThreadFactory(String name, int priority) {
mName = name;// 線程池的名稱
mPriority = priority;//線程池的優先順序
}
@Override
public Thread newThread(Runnable r) {
return new Thread(r, mName +"-"+mNumber.getAndIncrement()){
@Override
public void run() {
// 設置線程的優先順序
Process.setThreadPriority(mPriority);
super.run();
}
};
}
}
//以上是創建線程池的一個工具類,接下來為大家介紹本篇文章的重點,線程池的實現方式,具體實現方式如下所示(MyThreadPool.java):
package com.tcl.actionbar;

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
package com.tcl.actionbar;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ThreadFactory;

// 線程池的實現方式
public class MyThreadPool {
private final static int POOL_SIZE = 4;// 線程池的大小最好設置成為CUP核數的2N
private final static int MAX_POOL_SIZE = 6;// 設置線程池的最大線程數
private final static int KEEP_ALIVE_TIME = 4;// 設置線程的存活時間
private final Executor mExecutor;
public MyThreadPool() {
// 創建線程池工廠
ThreadFactory factory = new PriorityThreadFactory("thread-pool", android.os.Process.THREAD_PRIORITY_BACKGROUND);
// 創建工作隊列
BlockingQueue<Runnable> workQueue = new LinkedBlockingDeque<Runnable>();
mExecutor = new ThreadPoolExecutor(POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, workQueue, factory);
}
// 在線程池中執行線程
public void submit(Runnable command){
mExecutor.execute(command);
}
}

❸ Android 線程池的封裝

GlobalThreadPools.java:

調用:

線程池
線程池概念來源於Java中的Executor,它是一個介面,真正的實現為ThreadPoolExecutor。ThreadPoolExecutor提供了一系列參數來配置線程池。
優點
1:重用線程池中的線程,線程在執行完任務後不會立刻銷毀,而會等待另外的任務,這樣就不會頻繁地創建、銷毀線程和調用GC。。
2:有效控制線程池的最大並發數,避免大量線程搶占資源出現的問題。
3:對多個線程進行統一地管理,可提供定時執行及指定間隔循環執行的功能。
ThreadPoolExecutor 有多個重載方法,但最終都調用了這個構造方法
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
參數:
corePoolSize:線程池中核心線程的數量;為了內存優化,在線程池維護了幾個重要的線程,不達到一定條件不開辟其餘線程
maximumPoolSize :線程池中最大線程數量:這個數量是包括核心線程的,當線程池中的正在執行的線程池達到了這個數字,再提交線程如果你不做特殊處理將會拋出異常
keepAliveTime:非核心線程的超時時長;當線程池中的非核心線程閑置時間超過這個值代表的時間後,將會被回收;同時如果調用ThreadPoolExecutor.allowCoreThreadTimeOut(true),那麼核心線程也會符合這個設置
unit:keepAliveTime值的單位,可以是時分秒等
workQueue:存放待執行的線程;你通過execute方法提交線程,但是這些線程還沒達到執行條件,那麼就會保存在這個隊列里
threadFactory:創建線程池的工廠;在這個工廠里,我們可以指定線程的一些信息
handler:線程提交拒絕策略;通常是線程池中的正在執行的線程數量已經達到了最大線程數或線程池關閉,如果不傳,默認是拋出一個RejectedExecutionException,所以最好傳下

推薦使用 Executors 的工廠方法來創建線程池,通過直接或間接的配置 ThreadPoolExecutor 的參數來構建線程池,常用的線程池有如下 4 種,newFixedThreadPool ,newCachedThreadPool,
newScheledThreadPool 和 newSingleThreadExecutor。

ThreadPoolExecutor 執行任務時大致遵循如下流程:
1.如果線程池中的線程數未達到核心線程數,則會立馬啟用一個核心線程去執行。
2.如果線程池中的線程數已經達到核心線程數,且任務隊列workQueue未滿,則將新線程放入workQueue中等待執行。
3.如果線程池中的線程數已經達到核心線程數但未超過線程池規定最大值,且workQueue已滿,則開啟一個非核心線程來執行任務。
4.如果線程池中的線程數已經超過線程池規定最大值,則拒絕執行該任務,採取飽和策略,並拋出RejectedExecutionException異常。

線程池大小:(N為CPU數量)
如果是CPU密集型應用,則線程池大小設置為N+1
如果是IO密集型應用,則線程池大小設置為2N+1
I/O密集型
指的是系統的CPU效能相對硬碟/內存的效能要好,大部分的狀況是 CPU 在等 I/O (硬碟/內存) 的讀/寫, CPU Loading 不高。
CPU密集型
指的是系統的 硬碟/內存 效能 相對 CPU 的效能 要好,大部分的狀況是 CPU Loading 100%,CPU 要讀/寫 I/O (硬碟/內存),I/O在很短的時間就可以完成,而 CPU 還有許多運算要處理,CPU Loading 很高。
獲取CPU數量的方法為:
Runtime.getRuntime().availableProcessors();

摘自:
https://blog.csdn.net/qq_30993595/article/details/84324681

❹ android 使用線程池注意什麼

[java] view plain


ExecutorService pool = Executors.newFixedThreadPool(2); //創建一個能放兩個線程的池子
Thread t1 = new Thread();
Thread t2 = new Thread();

pool.execute(t1);
pool.execute(t2);//這是非同步的

如果要想知道,t1和t2,都走完了。

需要這么寫

[java] view plain


pool.shutdown();//先關閉線程池,不會影響已運行的線程
while (true) {
if (pool.isTerminated()) {
//所有任務完成
break;
}
Thread.sleep(200);

還有一種寫法

[java] view plain


List<Future> list=new ArrayList<Future>();
list.add(exe.submit(new Runnable() {
@Override
public void run() {

}
}));
for(int i=0;i<list.size();i++){
try {
list.get(i).get();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
這種方法會阻礙主線程

❺ android中的線程池 怎麼用

Java的線程池對Android也是適用的
線程池的作用:
線程池作用就是限制系統中執行線程的數量。
根據系統的環境情況,可以自動或手動設置線程數量,達到運行的最佳效果;少了浪費了系統資源,多了造成系統擁擠效率不高。用線程池控制線程數量,其他線程
排隊等候。一個任務執行完畢,再從隊列的中取最前面的任務開始執行。若隊列中沒有等待進程,線程池的這一資源處於等待。當一個新任務需要運行時,如果線程
池中有等待的工作線程,就可以開始運行了;否則進入等待隊列。
為什麼要用線程池:
1.減少了創建和銷毀線程的次數,每個工作線程都可以被重復利用,可執行多個任務。
2.可以根據系統的承受能力,調整線程池中工作線線程的數目,防止因為消耗過多的內存,而把伺服器累趴下(每個線程需要大約1MB內存,線程開的越多,消耗的內存也就越大,最後死機)。

Java通過Executors提供四種線程池,分別為:
newCachedThreadPool創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。
newFixedThreadPool 創建一個定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待。
newScheledThreadPool 創建一個定長線程池,支持定時及周期性任務執行。
newSingleThreadExecutor 創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行。

1.newCachedThreadPool

/**
* 可以緩存線程池
*/
public static void Function1() {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 50; i++) {
final int index = i;
try {
Thread.sleep(100); // 休眠時間越短創建的線程數越多
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
executorService.execute(new Runnable() {

@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("active count = " + Thread.activeCount()
+ " index = " + index);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}

列印結果
active count = 2 index = 0
active count = 3 index = 1
active count = 4 index = 2
active count = 5 index = 3
active count = 6 index = 4
active count = 7 index = 5
active count = 8 index = 6
active count = 9 index = 7
active count = 10 index = 8
active count = 11 index = 9
active count = 11 index = 10
active count = 11 index = 11
active count = 11 index = 12
active count = 11 index = 13
active count = 11 index = 14
active count = 11 index = 15
active count = 11 index = 16
active count = 11 index = 17
active count = 11 index = 18
active count = 11 index = 19
active count = 11 index = 20
active count = 11 index = 21
active count = 11 index = 22
active count = 11 index = 23
active count = 11 index = 24
active count = 11 index = 25
active count = 11 index = 26
active count = 11 index = 27
active count = 11 index = 28
active count = 11 index = 29
active count = 11 index = 30
active count = 11 index = 31
active count = 11 index = 32
active count = 11 index = 33
active count = 11 index = 34
active count = 11 index = 35
active count = 11 index = 36
active count = 11 index = 37
active count = 11 index = 38
active count = 11 index = 39
active count = 11 index = 40
active count = 11 index = 41
active count = 11 index = 42
active count = 11 index = 43
active count = 11 index = 44
active count = 11 index = 45
active count = 11 index = 46
active count = 11 index = 47
active count = 11 index = 48
active count = 10 index = 49
從列印消息來看開始線程數在增加,後來穩定,可以修改休眠時間,休眠時間越短創建的線程數就越多,因為前面的還沒執行完,線程池中沒有可以執行的就需要創建;如果把休眠時間加大,創建的線程數就會少

2.newFixedThreadPool 根據傳入的參數創建線程數目
/**
* 定長線程池
*/
public static void Function2() {
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 30; i++) {
final int index = i;
executorService.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println("index = " + index
+ " thread count = " + Thread.activeCount());
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}

3.newScheledThreadPool
?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

/**
* 定長線程池,可做延時
*/
public static void Function3() {
ScheledExecutorService executorService = Executors
.newScheledThreadPool(5);
executorService.schele(new Runnable() {

@Override
public void run() {
System.out.println("delay 3 seconds" + " thread count = "
+ Thread.activeCount());
}
}, 3, TimeUnit.SECONDS);
}

/**
* 定期執行,可以用來做定時器
*/
public static void Function4() {
ScheledExecutorService executorService = Executors
.newScheledThreadPool(3);
executorService.scheleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out
.println("delay 1 seconds, and excute every 3 seconds"
+ " thread count = " + Thread.activeCount());
}
}, 1, 3, TimeUnit.SECONDS);
}
列印結果
?

1
2
3
4
5
6
7
8
9

delay 1 seconds, and excute every 3 seconds thread count = 2
delay 1 seconds, and excute every 3 seconds thread count = 3
delay 1 seconds, and excute every 3 seconds thread count = 4
delay 1 seconds, and excute every 3 seconds thread count = 4
delay 1 seconds, and excute every 3 seconds thread count = 4
delay 1 seconds, and excute every 3 seconds thread count = 4
delay 1 seconds, and excute every 3 seconds thread count = 4
delay 1 seconds, and excute every 3 seconds thread count = 4
delay 1 seconds, and excute every 3 seconds thread count = 4

4.newSingleThreadExecutor這個最簡單
?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

/**
* 單例線程
*/
public static void Function5() {
ExecutorService singleThreadExecutor = Executors
.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {

@Override
public void run() {
try {
System.out.println("index = " + index
+ " thread count = " + Thread.activeCount());
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}

列印結果:
?

1
2
3
4
5

index = 0 thread count = 2
index = 1 thread count = 2
index = 2 thread count = 2
index = 3 thread count = 2
index = 4 thread count = 2

❻ android 線程池 怎麼用

我覺得使用線程池最大的優點是我們可以對我們開啟的線程進行跟進,當我們不需要處理的時候可以將它shutdow掉,同時當我們定義了一個線程池之後,可以復用線程而不需要開啟更多線程,這點對於我們手機開發是至關重要的,你開啟的thread越多意味著你的app內存消耗越多,速度也就越來越慢,提高現有線程的復用是一個很棒的選擇

線程池中處理線程的類別較多如:

限制按順序來執行任務的線程池、一個一個任務的執行線程池、按指定個數來執行任務的線程池、創建一個可在指定時間里執行任務的線程池,亦可重復執行、按指定工廠模式來執行的線程池

❼ Android線程池ThreadPoolExecutor詳解

       傳統的多線程是通過繼承Thread類及實現Runnable介面來實現的,每次創建及銷毀線程都會消耗資源、響應速度慢,且線程缺乏統一管理,容易出現阻塞的情況,針對以上缺點,線程池就出現了。

       線程池是一個創建使用線程並能保存使用過的線程以達到復用的對象,簡單的說就是一塊緩存了一定數量線程的區域。

       1.復用線程:線程執行完不會立刻退出,繼續執行其他線程;
       2.管理線程:統一分配、管理、控制最大並發數;

       1.降低因頻繁創建&銷毀線程帶來的性能開銷,復用緩存在線程池中的線程;
       2.提高線程執行效率&響應速度,復用線程:響應速度;管理線程:優化線程執行順序,避免大量線程搶占資源導致阻塞現象;
       3.提高對線程的管理度;

       線程池的使用也比較簡單,流程如下:

       接下來通過源碼來介紹一下ThreadPoolExecutor內部實現及工作原理。

       線程池的最終實現類是ThreadPoolExecutor,通過實現可以一步一步的看到,父介面為Executor:

       其他的繼承及實現關系就不一一列舉了,直接通過以下圖來看一下:

       從構造方法開始看:

       通過以上可以看到,在創建ThreadPoolExecutor時,對傳入的參數是有要求的:corePoolSize不能小於0;maximumPoolSize需要大於0,且需要大於等於corePoolSize;keepAliveTime大於0;workQueue、threadFactory都不能為null。
       在創建完後就需要執行Runnable了,看以下execute()方法:

       在execute()內部主要執行的邏輯如下:
       分析點1:如果當前線程數未超過核心線程數,則將runnable作為參數執行addWorker(),true表示核心線程,false表示非核心線程;
       分析點2:核心線程滿了,如果線程池處於運行狀態則往workQueue隊列中添加任務,接下來判斷是否需要拒絕或者執行addWorker();
       分析點3:以上都不滿足時 [corePoolSize=0且沒有運行的線程,或workQueue已經滿了] ,執行addWorker()添加runnable,失敗則執行拒絕策略;
        總結一下:線程池對線程創建的管理,流程圖如下:

       在執行addWorker時,主要做了以下兩件事:
       分析點1:將runnable作為參數創建Worker對象w,然後獲取w內部的變數thread;
       分析點2:調用start()來啟動thread;
       在addWorker()內部會將runnable作為參數傳給Worker,然後從Worker內部讀取變數thread,看一下Worker類的實現:

       Worker實現了Runnable介面,在Worker內部,進行了賦值及創建操作,先將execute()時傳入的runnable賦值給內部變數firstTask,然後通過ThreadFactory.newThread(this)創建Thread,上面講到在addWorker內部執行t.start()後,會執行到Worker內部的run()方法,接著會執行runWorker(this),一起看一下:

       前面可以看到,runWorker是執行在子線程內部,主要執行了三件事:
       分析1:獲取當前線程,當執行shutdown()時需要將線程interrupt(),接下來從Worker內部取到firstTask,即execute傳入的runnable,接下來會執行;
       分析2:while循環,task不空直接執行;否則執行getTask()去獲取,不為空直接執行;
       分析3:對有效的task執行run(),由於是在子線程中執行,因此直接run()即可,不需要start();
       前面看到,在while內部有執行getTask(),一起看一下:

       getTask()是從workQueue內部獲取接下來需要執行的runnable,內部主要做了兩件事:
       分析1:先獲取到當前正在執行工作的線程數量wc,通過判斷allowCoreThreadTimeOut[在創建ThreadPoolExecutor時可以進行設置]及wc > corePoolSize來確定timed值;
       分析2:通過timed值來決定執行poll()或者take(),如果WorkQueue中有未執行的線程時,兩者作用是相同的,立刻返回線程;如果WorkQueue中沒有線程時,poll()有超時返回,take()會一直阻塞;如果allowCoreThreadTimeOut為true,則核心線程在超時時間沒有使用的話,是需要退出的;wc > corePoolSize時,非核心線程在超時時間沒有使用的話,是需要退出的;
       allowCoreThreadTimeOut是可以通過以下方式進行設置的:

       如果沒有進行設置,那麼corePoolSize數量的核心線程會一直存在。
        總結一下:ThreadPoolExecutor內部的核心線程如何確保一直存在,不退出?
       上面分析已經回答了這個問題,每個線程在執行時會執行runWorker(),而在runWorker()內部有while()循環會判斷getTask(),在getTask()內部會對當前執行的線程數量及allowCoreThreadTimeOut進行實時判斷,如果工作數量大於corePoolSize且workQueue中沒有未執行的線程時,會執行poll()超時退出;如果工作數量不大於corePoolSize且workQueue中沒有未執行的線程時,會執行take()進行阻塞,確保有corePoolSize數量的線程阻塞在runWorker()內部的while()循環不退出。
       如果需要關閉線程池,需要如何操作呢,看一下shutdown()方法:

       以上可以看到,關閉線程池的原理:a. 遍歷線程池中的所有工作線程;b. 逐個調用線程的interrupt()中斷線程(註:無法響應中斷的任務可能永遠無法終止)
       也可調用shutdownNow()來關閉線程池,二者區別:
       shutdown():設置線程池的狀態為SHUTDOWN,然後中斷所有沒有正在執行任務的線程;
       shutdownNow():設置線程池的狀態為STOP,然後嘗試停止所有的正在執行或暫停任務的線程,並返回等待執行任務的列表;
       使用建議:一般調用shutdown()關閉線程池;若任務不一定要執行完,則調用shutdownNow();
        總結一下:ThreadPoolExecutor在執行execute()及shutdown()時的調用關系,流程圖如下:

       線程池可以通過Executors來進行不同類型的創建,具體分為四種不同的類型,如下:

       可緩存線程池:不固定線程數量,且支持最大為Integer.MAX_VALUE的線程數量:

       1、線程數無限制
       2、有空閑線程則復用空閑線程,若無空閑線程則新建線程
       3、一定程度上減少頻繁創建/銷毀線程,減少系統開銷

       固定線程數量的線程池:定長線程池

       1、可控制線程最大並發數(同時執行的線程數)
       2、超出的線程會在隊列中等待。

       單線程化的線程池:可以理解為線程數量為1的FixedThreadPool

       1、有且僅有一個工作線程執行任務
       2、所有任務按照指定順序執行,即遵循隊列的入隊出隊規則

       定時以指定周期循環執行任務

       一般來說,等待隊列 BlockingQueue 有: ArrayBlockingQueue 、 LinkedBlockingQueue 與 SynchronousQueue 。
       假設向線程池提交任務時,核心線程都被佔用的情況下:
        ArrayBlockingQueue :基於數組的阻塞隊列,初始化需要指定固定大小。
       當使用此隊列時,向線程池提交任務,會首先加入到等待隊列中,當等待隊列滿了之後,再次提交任務,嘗試加入隊列就會失敗,這時就會檢查如果當前線程池中的線程數未達到最大線程,則會新建線程執行新提交的任務。所以最終可能出現後提交的任務先執行,而先提交的任務一直在等待。
        LinkedBlockingQueue :基於鏈表實現的阻塞隊列,初始化可以指定大小,也可以不指定。
       當指定大小後,行為就和 ArrayBlockingQueue一致。而如果未指定大小,則會使用默認的 Integer.MAX_VALUE 作為隊列大小。這時候就會出現線程池的最大線程數參數無用,因為無論如何,向線程池提交任務加入等待隊列都會成功。最終意味著所有任務都是在核心線程執行。如果核心線程一直被占,那就一直等待。
        SynchronousQueue :無容量的隊列。
       使用此隊列意味著希望獲得最大並發量。因為無論如何,向線程池提交任務,往隊列提交任務都會失敗。而失敗後如果沒有空閑的非核心線程,就會檢查如果當前線程池中的線程數未達到最大線程,則會新建線程執行新提交的任務。完全沒有任何等待,唯一制約它的就是最大線程數的個數。因此一般配合Integer.MAX_VALUE就實現了真正的無等待。
       但是需要注意的是, 進程的內存是存在限制的,而每一個線程都需要分配一定的內存。所以線程並不能無限個。

❽ Android線程池的使用

在Android中有主線程和子線程的區分。主線程又稱為UI線程,主要是處理一些和界面相關的事情,而子線程主要是用於處理一些耗時比較大的一些任務,例如一些網路操作,IO請求等。如果在主線程中處理這些耗時的任務,則有可能會出現ANR現象(App直接卡死)。

線程池,從名字的表明含義上我們知道線程池就是包含線程的一個池子,它起到新建線程、管理線程、調度線程等作用。

既然Android中已經有了線程的概念,那麼為什麼需要使用線程池呢?我們從兩個方面給出使用線程池的原因。

在Android中線程池就是ThreadPoolExecutor對象。我們先來看一下ThreadPoolExecutor的構造函數。

我們分別說一下當前的幾個參數的含義:
第一個參數corePoolSize為 核心線程數 ,也就是說線程池中至少有這么多的線程,即使存在的這些線程沒有執行任務。但是有一個例外就是,如果在線程池中設置了allowCoreThreadTimeOut為true,那麼在 超時時間(keepAliveTime) 到達後核心線程也會被銷毀。
第二個參數maximumPoolSize為 線程池中的最大線程數 。當活動線程數達到這個數後,後續添加的新任務會被阻塞。
第三個參數keepAliveTime為 線程的保活時間 ,就是說如果線程池中有多於核心線程數的線程,那麼在線程沒有任務的那一刻起開始計時,如果超過了keepAliveTime,還沒有新的任務過來,則該線程就要被銷毀。同時如果設置了allowCoreThreadTimeOut為true,該時間也就是上面第一條所說的 超時時間
第四個參數unit為 第三個參數的計時單位 ,有毫秒、秒等。
第五個參數workQueue為 線程池中的任務隊列 ,該隊列持有由execute方法傳遞過來的Runnable對象(Runnable對象就是一個任務)。這個任務隊列的類型是BlockQueue類型,也就是阻塞隊列,當隊列的任務數為0時,取任務的操作會被阻塞;當隊列的任務數滿了(活動線程達到了最大線程數),添加操作就會阻塞。
第六個參數threadFactory為 線程工廠 ,當線程池需要創建一個新線程時,使用線程工廠來給線程池提供一個線程。
第七個參數handler為 拒絕策略 ,當線程池使用有界隊列時(也就是第五個參數),如果隊列滿了,任務添加到線程池的時候的一個拒絕策略。

可以看到FixedThreadPool的構建調用了ThreadPoolExecutor的構造函數。從上面的調用中可以看出FixedThreadPool的幾個特點:

可以看到CacheThreadPool的構建調用了ThreadPoolExecutor的構造函數。從上面的調用中可以看出CacheThreadPool的幾個特點:

可以看到ScheledThreadPoolExecutor的構建調用了ThreadPoolExecutor的構造函數。從上面的調用中可以看出ScheledThreadPoolExecutor的幾個特點:

可以看到SingleThreadExecutor的構建調用了ThreadPoolExecutor的構造函數。從上面的調用中可以看出SingleThreadExecutor的幾個特點:

❾ Android多線程的四種方式:Handler、AsyncTask、ThreadPoolExector、IntentService

     非同步通信機制,將工作線程中需更新UI的操作信息 傳遞到 UI主線程,從而實現 工作線程對UI的更新處理,最終實現非同步消息的處理。Handler不僅僅能將子線程的數據傳遞給主線程,它能實現任意兩個線程的數據傳遞。

(1)Message

    Message 可以在線程之間傳遞消息。可以在它的內部攜帶少量數據,用於在不同線程之間進行數據交換。除了 what 欄位,還可以使用 arg1 和 arg2 來攜帶整型數據,使用 obj 來攜帶 Object 數據。

(2) Handler

    Handler 作為處理中心,用於發送(sendMessage 系列方法)與處理消息(handleMessage 方法)。

(3) MessageQueue

    MessageQueue 用於存放所有通過 Handler 發送的消息。這部分消息會一直存放在消息隊列中,直到被處理。每個線程中只會有一個 MessageQueue 對象

(4) Looper

    Looper 用於管理 MessageQueue 隊列,Looper對象通過loop()方法開啟了一個死循環——for (;;){},不斷地從looper內的MessageQueue中取出Message,並傳遞到 Handler 的 handleMessage() 方法中。每個線程中只會有一個 Looper 對象。

    AsyncTask 是一種輕量級的任務非同步類,可以在後檯子線程執行任務,且將執行進度及執行結果傳遞給 UI 線程。

(1)onPreExecute()

    在 UI 線程上工作,在任務執行 doInBackground() 之前調用。此步驟通常用於設置任務,例如在用戶界面中顯示進度條。

(2)doInBackground(Params... params)

    在子線程中工作,在 onPreExecute() 方法結束後執行,這一步被用於在後台執行長時間的任務,Params 參數通過 execute(Params) 方法被傳遞到此方法中。任務執行結束後,將結果傳遞給 onPostExecute(Result) 方法,同時我們可以通過 publishProgress(Progress) 方法,將執行進度發送給 onProgressUpdate(Progress) 方法。

(3)onProgressUpdate(Progress... values)

    在 UI 線程上工作,會在 doInBackground() 中調用 publishProgress(Progress) 方法後執行,此方法用於在後台計算仍在執行時(也就是 doInBackgound() 還在執行時)將計算執行進度通過 UI 顯示出來。例如,可以通過動畫進度條或顯示文本欄位中的日誌,從而方便用戶知道後台任務執行的進度。

(4)onPostExecute(Result result)

    在 UI 線程上工作,在任務執行完畢(即 doInBackground(Result) 執行完畢)並將執行結果傳過來的時候工作。

使用規則:

(1)AsyncTask 是個抽象類,所以要創建它的子類實現抽象方法

(1)AsyncTask 類必須是在 UI 線程中被載入,但在Android 4.1(API 16)開始,就能被自動載入完成。

(2)AsyncTask 類的實例對象必須在 UI 線程中被創建。

(3)execute() 方法必須是在 UI 線程中被調用。

(4)不要手動調用方法 onPreExecute()、onPostExecute()、doInBackground()、onProgressUpdate()

(5)任務只能執行一次(如果嘗試第二次執行,將拋出異常)。即一個AsyncTask對象只能調用一次execute()方法。

原理:

          其源碼中原理還是 Thread 與 Handler 的實現,其包含 兩個線程池,一個 Handler,如下所示:

名稱類型作用

SERIAL_EXECUTOR線程池分發任務,串列分發,一次只分發一個任務

THREAD_POOL_EXECUTOR線程池執行任務,並行執行,執行的任務由 SERIAL_EXECUTOR 分發

InternalHandlerHandler負責子線程與主線程的溝通,通知主線程做 UI 工作

    一方面減少了每個並行任務獨自建立線程的開銷,另一方面可以管理多個並發線程的公共資源,從而提高了多線程的效率。所以ThreadPoolExecutor比較適合一組任務的執行。Executors利用工廠模式對ThreadPoolExecutor進行了封裝。

Executors提供了四種創建ExecutorService的方法,他們的使用場景如下:

1. Executors.newFixedThreadPool()

    創建一個定長的線程池,每提交一個任務就創建一個線程,直到達到池的最大長度,這時線程池會保持長度不再變化。

當線程處於空閑狀態時,它們並不會被回收,除非線程池被關閉。當所有的線程都處於活動狀態時,新任務都會處於等待狀態,直到有線程空閑出來。

只有核心線程並且不會被回收,能夠更加快速的響應外界的請求。

2. Executors.newCachedThreadPool()

    創建一個可緩存的線程池,如果當前線程池的長度超過了處理的需要時,它可以靈活的回收空閑的線程,當需要增加時,它可以靈活的添加新的線程,而不會對池的長度作任何限制

    線程數量不定的線程池,只有非核心線程,最大線程數為 Integer.MAX_VALUE。當線程池中的線程都處於活動狀態時,線程池會創建新的線程來處理新任務,否則利用空閑的線程來處理新任務。線程池中的空閑線程具有超時機制,為 60s。

    任務隊列相當於一個空集合,導致任何任務都會立即被執行,適合執行大量耗時較少的任務。當整個線程池都處於限制狀態時,線程池中的線程都會超時而被停止。

3. Executors.newScheledThreadPool()

    創建一個定長的線程池,而且支持定時的以及周期性的任務執行,類似於Timer。

    非核心線程數沒有限制,並且非核心線程閑置的時候立即回收,主要用於執行定時任務和具有固定周期的重復任務。

4. Executors.newSingleThreadExecutor()

    創建一個單線程化的executor,它只創建唯一的worker線程來執行任務

    只有一個核心線程,保證所有的任務都在一個線程中順序執行,意義在於不需要處理線程同步的問題。

    一般用於執行後台耗時任務,當任務執行完成會自動停止;同時由於它是一個服務,優先順序要遠遠高於線程,更不容易被系統殺死,因此比較適合執行一些高優先順序的後台任務。

使用步驟:創建IntentService的子類,重寫onHandleIntent方法,在onHandleIntent中執行耗時任務

    原理:在源碼實現上,IntentService封裝了HandlerThread和Handler。onHandleIntent方法結束後會調用IntentService的stopSelf(int startId)方法嘗試停止服務。

    IntentService的內部是通過消息的方式請求HandlerThread執行任務,HandlerThread內部又是一種使用Handler的Thread,這就意味著IntentService和Looper一樣是順序執行後台任務的

(HandlerThread:封裝了Handler + ThreadHandlerThread適合在有需要一個工作線程(非UI線程)+任務的等待隊列的形式,優點是不會有堵塞,減少了對性能的消耗,缺點是不能同時進行多個任務的處理,需要等待進行處理。處理效率低,可以當成一個輕量級的線程池來用)

❿ Android中的線程池

 線程池的好處

1、重用線程池中的線程,避免線程的創建與銷毀帶來的性能開銷

2、能有效控制線程池的最大並發數,避免大量線程因搶占資源而導致的阻塞

3、能對線程進行簡單的管理,提供定時或者指定間隔時間、循環執行等操作

線程池的概率來自於java的Executor介面,實現類是ThreadPoolExecutor, 它提供一系列的參數來配置線程池,以此構建不同的線程池。Android的線程池分4類,都是通過Executors所提供的工廠方法來得到。

ThreadPoolExecutor有四個構造函數,下面這個是最常用的

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnnable> workQueue, ThreadFactory threadFactory)

corePoolSize

線程池中的核心線程數,默認情況下核心線程會在線程池中一直存活,即使他們處於閑置狀態。如果設置ThreadPoolExecutor 中的allowCoreThreadTimeOut = true, 核心線程在等待新任務到來時有超時機制,時間超過keepAliveTime所指定的時間後,核心線程會終止。

maximumPoolSize

最大線程數

keepAliveTime

非核心線程閑置的超時時間,超過這個時間,非核心線程會被回收。核心線程則要看allowCoreThreadTimeOut屬性的值。

unit

時間單位

workQueue

線程池中的工作隊列

threadFactory

線程工廠,為線程池提供創建新線程的功能。

舉個例子,我們常用的okhttp內部也是使用了線程池,它的ThreadPoolExecutor主要是定義在Dispatcher類裡面。 使用的是CachedThreadPool。

executorService = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS, SynchronousQueue(), ThreadFactory("okhttp Dispatcher", false))

1、FixedThreadPool

通過Executors的newFixedThreadPool()創建,這是一個線程數量固定的線程池,裡面所有的線程都是核心線程。

public static ExecutorService newFixedThreadPool(int nThreads){

return new ThreadPoolExecutor(nThreads, nThreads, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())

}

2、CachedThreadPool

通過Executors的newCacheThreadPool()創建,這是一個線程數量不定的線程池,裡面所有的線程都是非核心線程。最大線程數是無限大,當線程池中的線程都處於活動狀態時,新的task會創建新的線程來處理,否則就使用空閑的線程處理,所有的線程都是60s的超時時間,超時後會自動回收。

public static ExecutorService newFixedThreadPool(){

return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>())

}

3、ScheledThreadPool

通過Executors的newScheledThreadPool()創建, 核心線程固定,非核心線程無限大,當非核心線程空閑時,會立即被回收。適合做定時任務或者固定周期的重復任務。

public static ExecutorService newScheledThreadPool(int corePoolSize){

return new ThreadPoolExecutor(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.SECONDS, new DelayedWorkQueue())

}

4、SingleThreadExcecutor

通過Executors的newSingleThreadPool()創建,內部只有一個核心線程。

public static ExecutorService newFixedThreadPool(){

return new ThreadPoolExecutor(1, 1, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())

}

課外知識:LinkedBlockingQueue

LinkedBlockingQueue是由鏈表組成的阻塞隊列,內部head 指向隊列第一個元素,last指向最後一個元素。入隊和出隊都會加鎖阻塞,都是使用了不同的鎖。

DelayedWorkQueue

延時隊列,隊內元素必須是Delayed的實現類。對內元素會按照Delayed時間進行排序,對內元素只有在delayed時間過期了才能出隊。

入隊的時候不阻塞隊列,出隊的時候,如果隊列為空或者隊列里所有元素都等待時間都沒有到期,則該線程進入阻塞狀態。

熱點內容
我的世界外置登錄在伺服器如何顯示皮膚 發布:2025-01-09 20:18:36 瀏覽:283
一個文件夾一個窗口 發布:2025-01-09 20:02:08 瀏覽:479
java的indexof 發布:2025-01-09 19:51:14 瀏覽:610
光遇ios國際服怎麼登錄安卓 發布:2025-01-09 19:44:24 瀏覽:778
手機如何破解無線密碼 發布:2025-01-09 19:36:52 瀏覽:49
java貓 發布:2025-01-09 19:35:13 瀏覽:130
linux埠號命令 發布:2025-01-09 19:21:55 瀏覽:530
輸入虛擬手機伺服器地址怎麼填 發布:2025-01-09 18:58:50 瀏覽:349
dede換資料庫 發布:2025-01-09 18:53:23 瀏覽:263
sql2000資料庫置疑修復 發布:2025-01-09 18:35:54 瀏覽:411