Android中線程與線程池

在Java中默認情況下一個進程只有一個線程,也就是主線程,其他線程都是子線程,也叫工作線程。Android中的主線程主要處理和界面相關的事情,而子線程則往往用於執行耗時操作。線程的創建和銷燬的開銷較大,所以如果一個進程要頻繁地創建和銷燬線程的話,都會採用線程池的方式。



Android中線程的形態


傳統的Thread

這是Java本身就支持的類,自定義化程度高,但是所有的功能都需要自己維護。

AsyncTask

AsyncTask常用於可以在幾秒鐘完成的後臺任務。

HandlerThread

HandlerThread繼承了Thread,是一種可以使用Handler的Thread,它的實現就是在run方法中通過Looper.prepare()來創建消息隊列,並通過Looper.loop()來開啓消息循環,這樣在實際的使用中就允許在HandlerThread中創建Handler了。外界可以通過Handler的消息方式通知HandlerThread執行一個具體的任務。
HandlerThread的一個應用場景就是用在IntentService中。

HandlerThread的run方法是一個無限循環,因此當明確不需要再使用HandlerThread的時候,可以通過它的quit或者quitSafely方法來終止線程的執行,這是一個良好的編程習慣。

IntentService

IntentService是一個特殊的Service,它繼承自Service並且是個抽象類,要使用它就要創建它的子類。與AsyncTask不同的是,IntentService用於需要長時間執行的任務,因爲他是Service,所以他的優先級比單純的線程高很多。
IntentService的onCreate方法中會創建HandlerThread,並使用HandlerThread的Looper來構造一個Handler對象ServiceHandler,這樣通過ServiceHandler對象發送的消息最終都會在HandlerThread中執行。IntentService會將Intent封裝到Message中,通過ServiceHandler發送出去,在ServiceHandler的handleMessage方法中會調用IntentService的抽象方法onHandleIntent,所以IntentService的子類都要是實現這個方法。

Android中的線程池


線程池的好處

(1)重用線程池中的線程,避免因爲線程的創建與銷燬帶來的性能損耗。
(2)能有效的控制線程的最大併發,避免大量線程之間因爲搶奪系統資源而帶來的性能損耗而導致阻塞現象。
(3)能對線程進行簡單的管理,並提供定時執行,以及提供定時執行以及指定間隔循環等功能。


Android中的線程池概念來源Java的Executor,Executor是一個接口,真正的線程池實現ThreadPoolExecutor.ThreadPoolExecutor提供了一系列參數來配置線程池,通過不同的參數創建不同的線程,從線程池的功能特性來說,Android的線程池可以分爲4類.這四類線程池可以通過Executors所提供的工廠方法來得到.


ThreadPoolExecutor


ThreadPoolExecutor是線程的真正實現,他的的構造裏面提供了一系列參數來配置線程池,下面一一對構造中的參數進行分析:

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

corePoolSize:
線程池的核心線程數,默認情況下核心線程在線程池中會一直存活,即使他處於閒置狀態,如果將ThreadPoolExecutor的allowCoreThreadTimerout屬性設置爲True,那麼閒置的線程會有超時策略,這個時間由keepAliveTime所決定,當時間超過keepAliveTime之後,核心線程數會被終止。

maximumPoolSize:
最大線程數,當活動線程數達到這個數值後,後續的任務將會被阻塞。

keepAliveTime:
非核心線程閒置時的超時時長,超過這個時長,閒置的非核心線程就會被回收。

unit:
用於指定keepAliveTime參數的時間單位,有TimeUnit.MILLISECONDS、TimeUnit.SECONDS、TimeUnit.MINUTES等。

BlockingQueue:
任務隊列,通過線程池的execute方法提交的Runnable對象會存儲在這個參數中。

ThreadFactory :
線程工廠,爲線程池提供創建新線程的功能。它是一個接口,它只有一個方法Thread newThread(Runnable r).

RejectedExecutionHandler :
當線程池無法執行新任務時,可能是由於任務隊列已滿或者是無法成功執行任務,這個時候就會調用這個Handler的rejectedExecution方法來通知調用者,默認情況下,rejectedExecution會直接拋出一個rejectedExecutionException。


ThreadPoolExecutor執行任務規則

(1)如果線程池中的線程數未達到核心線程的數量,那麼會直接啓動一個核心線程來執行任務

(2)如果線程池中的線程數量已經達到或者超過核心線程的數量,那麼任務會被插入到任務隊列中排隊等待執行

(3)如果在步驟2中無法將任務插入到的任務隊列中,可能是任務隊列已滿,這個時候如果線程數量沒有達到規定的最大值,那麼會立刻啓動非核心線程來執行這個任務

(4)如果步驟3中線程數量已經達到線程池規定的最大值,那麼就拒絕執行此任務,ThreadPoolExecutor會調用RejectedExecutionHandler的rejectedExecution方法來通知調用者。


AsyncTask中的THREAD_POOL_EXECUTOR線程池的配置情況:

public abstract class AsyncTask<Params, Progress, Result> {

    private static final String LOG_TAG = "AsyncTask";
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE = 1;
    ....
}

從上面AsyncTask源碼中可以看出:
corePoolSize=CPU核心數+1;

maximumPoolSize=2倍的CPU核心數+1;

核心線程無超時機制,非核心線程在閒置時間的超時時間爲1s;

任務隊列的容量爲128。


線程池分類:

FixedThreadPool:線程數量固定的線程池,它只有核心線程;

CachedThreadPool:線程數量不固定的線程池,它只有非核心線程;

ScheduledThreadPool:核心線程數量固定,非核心線程數量沒有限制的線程池,主要用於執行定時任務和具有固定週期的任務;

SingleThreadPool:只有一個核心線程的線程池,確保了所有的任務都在同一個線程中按順序執行。


下面通過實例來演示系統預裝的4中線程池的使用:

private void runThreadPool() {
    Runnable command = new Runnable() {
         @Override
         public void run() {
             SystemClock.sleep(2000);
         }
    };

    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
    fixedThreadPool.execute(command);

    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    cachedThreadPool.execute(command);

    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4);
    // 2000ms後執行command
    scheduledThreadPool.schedule(command, 2000, TimeUnit.MILLISECONDS);
    // 延遲10ms後,每隔1000ms執行一次command
    scheduledThreadPool.scheduleAtFixedRate(command, 10, 1000, TimeUnit.MILLISECONDS);

    ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    singleThreadExecutor.execute(command);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章