1. 程式人生 > >Android執行緒與執行緒池的這些你知道嗎?

Android執行緒與執行緒池的這些你知道嗎?

在Android中,執行緒分為主執行緒和子執行緒,主介面用於與使用者互動,進行UI的相關操作,而子執行緒則負責耗時操作。如果在主執行緒中進行耗時操作,就會使程式無法及時的響應。因此耗時操作必須放在子執行緒中進行。

1、主執行緒和子執行緒

主執行緒是指程序所有用的執行緒,在Android中即指進行UI與使用者互動的執行緒就是主執行緒。因此在Android開發中,需要竟可能的把耗時操作,網路請求訪問操作,資料庫讀取操作等放在子執行緒,以避免主執行緒長期處於佔用狀態以降低使用者體驗。系統要求網路訪問必須在子執行緒中進行,否則會丟擲NetworkOnMainThreadException異常。

2、執行緒形態

Android中的執行緒形態有傳統的Thread,AsyncTask,HandlerThread和IntentService。

2.1、AsyncTask

AsyncTask封裝了Thread和Handler,必須在主執行緒進行呼叫,它可以在子執行緒中執行任務,然後將執行的結果傳遞給主執行緒並更新UI。但AsyncTask並不適合執行特別耗時的任務。

2.1.1、引數:

AsyncTask是一個泛型類,提供了三個泛型引數,Params ,Progress 和Result。

  • Params表示引數的型別
  • Progress表示後臺任務的執行進度的型別
  • Result表示後臺任務返回結果的型別

AsyncTask的宣告:

public abstract class Asynctask<Params,Progress,Result>

2.1.2、方法:

AsyncTask提供了一些核心方法:

  • onPreExecute() 在主執行緒中呼叫用來進行非同步任務的準備操作。
  • doInBackground(Params …… params) 在執行完onPreExecute()後進行子執行緒任務時自動呼叫,Params表示非同步任務的輸入引數。在方法中可以通過publishProgress更新任務的完成進度,同時在結束呼叫後會返回結果給onPostExecute()方法。
  • onProgressUpdate(Params …… params) 在主執行緒中用於顯示任務進行的進度,在publishProgress()方法中被呼叫。
  • onProgressExecute(Result result) 在主執行緒中使用者獲取任務結束後回返的結果,即doInBackground的返回值。
  • onCancelled() 在主執行緒中執行,當非同步任務被取消後不會執行onProgressExecute方法而會執行onCancelled方法。

2.1.3、呼叫:

AsyncTask的使用步驟如下: 1.建立AsyncTask子類,具體實現其核心方法 2.建立子類的例項物件 3.呼叫execute執行非同步執行緒任務

2.1.4、AsyncTask的限制:

1.必須在主執行緒載入,即第一次訪問AsyncTask必須在主執行緒,物件必須在主執行緒建立 2.execute必須在UI執行緒中呼叫 3.不能再程式中直接呼叫onPreExecute(),onPostExecute(),doInBackground和onProgressUpdate方法。 4.一個AsyncTask方法只能使用一次

2.1.5、AsyncTask的工作原理:

  • execute方法
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
}

public final AsyncTask<Params,Progress,Result>executeOnExecutor(Executor exec, Params...params){
    if (mStatus != Status.PENDING) {
        switch (mStatus) {
            case RUNNING:
                throw new IllegalStateException("Cannot execute task:"
                    + " the task is already running.");
            case FINISHED:
                throw new IllegalStateException("Cannot execute task:"
                    + " the task has already been executed "
                    + "(a task can be executed only once)");
        }
    }
    mStatus=Status.RUNNING;
    onPreExecute();
    mWorker.mParams=params;
    exec.execute(mFuture);
     return this;
}

在execute方法中,會檢測AsyncTask的當前狀態,如果當前為RUNNING或FINISHED狀態,系統會丟擲異常,當為空閒狀態,則置為RUNNING狀態。 置為RUNNING狀態後會呼叫onPreExecute方法,同時將引數Params傳遞給mWorker的mParams。之後呼叫exec.execute,並傳入mFuture,其中exec就是傳進來的sDefaultExecutor。

  • sDefaultExecutor sDefaultExecutor是一個序列的執行緒池,一個程序中的所有的AsyncTask全部在這個序列執行緒池中排隊執行,在executeOnExecute方法中,onPreExecute方法最先執行。
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

private static class SerialExecutor implements Executor {

    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
    Runnable mActive;

    public synchronized void execute(final Runnable r) {
        mTasks.offer(new Runnable() {
            public void run() {
                try {
                    r.run();
                } finally {
                    scheduleNext();
                }
            }
        });

        if (mActive == null) {
            scheduleNext();
        }
    }

    protected synchronized void scheduleNext() {
        if ((mActive = mTasks.poll()) != null) {
            THREAD_POOL_EXECUTOR.execute(mActive);
        }
    }
}

mTasks代表了SerialExecutor這個序列執行緒池的任務快取佇列,之後用offer向任務快取佇列中添加了一個任務,呼叫了r的run方法,r就是傳入的mFuture,而mFuture的run方法內部會呼叫MWorker的call方法,接著呼叫doInBackground方法,開始執行後臺任務。執行結束後會呼叫scheduleNext方法,執行下一個任務。另外mActive表示了AsyncTask的物件,如果MActive為null,則同樣會執行scheduleNext方法。在scheduleNext方法中,若快取佇列不為空,則從佇列中取出任務執行。 綜上,SerialExecutor的工作是將任務加入快取佇列中,而執行任務的是THREAD_POOL_EXECUTOR。

  • THREAD_POOL_EXECUTOR
public static final Executor THREAD_POOL_EXECUTOR
        = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

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;

private static final ThreadFactory sThreadFactory = new ThreadFactory() {
    private final AtomicInteger mCount = new AtomicInteger(1);

    public Thread newThread(Runnable r) {
        return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
    }
};

private static final BlockingQueue<Runnable> sPoolWorkQueue =
        new LinkedBlockingQueue<Runnable>(128);

即corePoolSize的CPU數加一,maxumumPoolSize的CPU數二倍加一,存活1s,任務快取佇列為LinkedBlockingQueue。

  • postResult方法
private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

首先用getHandler方法獲取AsyncTask獲取內部包含的sHandler,然後傳送MESSAGE_POST_RESULT訊息。

  • sHandler
private static final InternalHandler sHandler = new InternalHandler();

private static class InternalHandler extends Handler {
    public InternalHandler() {
        super(Looper.getMainLooper());
    }

    @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
        @Override
        public void handleMessage(Message msg) {
            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
            switch (msg.what) {
                case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
} 

sHandler是一個靜態的Handler物件,為了sHandler能夠執行環境從後臺切換到主執行緒,則應使用主執行緒的Looper,在主執行緒中建立sHandler。sHandler收到MESSAGE_POST_RESULT後,會呼叫finish方法。原始碼如下:

  • finish
private void finish(Result result) {
    if (isCancelled()) {
        onCancelled(result);
    } 
    else {
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;
} 

呼叫isCancelled()判斷任務是否取消,如果取消則呼叫 onCancelled(result),否則呼叫onPostExecute(result)。同時將mStatus設為FINISHED,表示物件執行完畢。

2.2、HandlerThread

2.2.1、簡介及實現

HandlerThread繼承了Thread,能夠使用Handler,實現簡單,節省系統資源開銷。 實現如下:

HandlerThread thread = new HandlerThread("MyHandlerThread");
thread.start();
mHandler = new Handler(thread.getLooper());
mHandler.post(new Runnable(){...});

2.2.2、原始碼及分析

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

}

它建立了一個訊息佇列,外界需要通過Handler的訊息通知它執行一個任務,由於HandlerThread的run方法是一個無限迴圈方法,所以可以通過quit方法終止執行緒的執行。

2.3、IntentService

IntentService是特殊的Service,繼承了Service,因為IntentService是一個抽象類,所以必須建立IntentService的子類才能使用。 同時,IntentService是服務,所以在執行時,優先順序較高。 IntentService封裝了HandlerThread和Handler。

2.3.1、使用

1.定義IntentService子類,傳入執行緒名稱,複寫onHandlerIntent()方法。 2.在Manifest.xml中註冊 3.在Activity中開啟服務

2.3.2、原始碼分析

  • onCreate 在IntentThread被第一次啟動時,會呼叫相應的onCreate方法。具體如下:
@Override
public void onCreate() {
    super.onCreate();
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();

    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper); 
}

首先例項化新執行緒,然後獲得工作執行緒的 Looper,並且構造一個Handler物件mServiceHandler,通過mServiceHandler傳送的訊息都會在HandlerThread中執行。

  • onStartCommand

每次啟動IntentService都會呼叫onStartCommand方法,用於處理每個後臺任務的Intent。

public int onStartCommand(Intent intent, int flags, int startId) {

    onStart(intent, startId);
    return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}

public void onStart(Intent intent, int startId) {

    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    msg.obj = intent;
    mServiceHandler.sendMessage(msg);
}

可以看出在onStartCommand中會呼叫onStart 方法,在onStart方法中,獲得ServiceHandler訊息的引用,後將訊息包裝到msg中,之後傳送訊息。這個訊息會在HandlerThread中被處理。

  • ServiceHandler方法
private final class ServiceHandler extends Handler {

    public ServiceHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {

        onHandleIntent((Intent)msg.obj);
        stopSelf(msg.arg1);
    }

}

IntentService的onHandleIntent方法是一個抽象方法,需要實現,作用是從Intent中區分具體任務並執行,呼叫執行完任務後,stopSelf會直接停止服務,當存在多個任務時,stopSelf則會在最後一個任務執行完畢後停止服務。

3、執行緒池

在實際使用中,執行緒池往往更加放標,和執行緒相比,執行緒池效能開銷小,可避免因為大量執行緒搶佔資源而堵塞,也更容易管理。

java中執行緒池的介面是ExecutorService,預設實現是ThreadPoolExecutor。

3.1、ThreadPoolExecutor

ThreadPoolExecutor是執行緒池的實現,構造方法如下

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

  • corePoolSize

核心執行緒數,核心執行緒會線上程池中一直存活。若將allowCoreThreadTimeOut設定為true,那麼核心執行緒也將有timepout,會在超時後被殺死。

  • maximumPoolSize

最大執行緒數。

  • keepAliveTime

非核心執行緒限制的超時時長,超過設定時間後非核心執行緒會被收回,allowCoreThreadTimeOut設定為true後核心執行緒也會被收回。

  • unit 時間的引數單位
  • workQueue

任務佇列,通過執行緒池的execute方法提交的Runnable物件儲存在其中

  • threadFactory

執行緒工廠,為執行緒池建立執行緒

ThreadPoolExecutor在執行執行緒任務是需滿足一定的規則

  • 首先使用核心執行緒,在核心執行緒不夠時才啟用新執行緒
  • 當任務書大於核心執行緒數量,那麼會被插入等待佇列中
  • 如果不能插入等待佇列,且執行緒數量未達到最大執行緒數,則會開啟新執行緒
  • 若無法插入等待佇列且無法建立新執行緒,則請求會被拒絕

3.2、執行緒池的分類

執行緒池分為四種不同的功能,分別是FixedThreadPool、CachedThreadPool、ScheduledThreadPool、SingkeThreadExecutor。

  • FixedThreadPool

通過execute的newFixedThreadPool方法建立,固定大小的執行緒池,每次提交任務都會建立新的執行緒,直到池中執行緒數目達到最大。如果有一個執行緒異常結束後,會產生一個新的執行緒補充進去。能夠更快地相應外界請求。 具體實現如下:

public static ExecutorSrevice newFixedThreadPool(int nThreads){
    return new ThreadPoolExecutor(nThread,nThreads,
                            0L,TimeUnit.MILLISECINDS,
                            new LinkedBlockingQueue<Runnable>());
}

  • CachedThreadPool 一個可以根據需要建立執行緒的執行緒池,對於很多短期的非同步任務,將有效提高效能,呼叫execute()將重用已構造的執行緒,如果沒有執行緒可用,將創造一個新的執行緒並加入執行緒池,並移除超過60s未使用的執行緒。適合執行耗時少的任務。 具體實現如下:
public static ExecutorService newCachedThreadPool(){
    reutrn new ThreadPoolExecutor(0,Interger.MAX_VALUE,
                            60L,TimeUnit.SECONDS,
                            new SynchronousQueue<Runnable>());
}

  • ScheduledThreadPool 核心執行緒有限,非核心執行緒數無線,建立一個大小無限的執行緒池,此執行緒池支援定時以及週期性執行任務的需求。 具體實現如下:
public static ScheduledThreadPool newScheduledThreadPool(int corePoolSize){
    reutrn new ScheduledThreadPool(corePoolSize);
}

public ScheduledThreadPoolExecutor(int corePoolSize){
    super(corePoolSize,Integer.MAX_VALUE,0,MANOSECONDS,new DelayWorkQueue());
}

  • SingkeThreadExecutor 建立單執行緒池,即執行緒池中只有一個執行緒,所有的任務是序列執行,如果池中執行緒因異常結束,會有一個新的執行緒來代替。以此保證了任務按提交順序執行。 具體實現如下:
public static ExecutorService newScheduledThreadExecutor(){
    reutrn new FinalizeableDelegatedExecutorService
            (new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECINDS,new LinkedBlockingQueue<Runnable>()));
}

最後

如果你看到了這裡,覺得文章寫得不錯就給個讚唄!歡迎大家評論討論!如果你覺得那裡值得改進的,請給我留言。一定會認真查詢,修正不足,定期免費分享技術乾貨。喜歡的小夥伴可以關注一下哦。謝謝!

相關推薦

Android執行執行這些知道

在Android中,執行緒分為主執行緒和子執行緒,主介面用於與使用者互動,進行UI的相關操作,而子執行緒則負責耗時操作。如果在主執

通常我們匯入包時java.awtjava.util的區別知道

1.相同點:Java.util和Java.awt都是Java的標準庫包  不同點:Java.util通常包含的是一些工具類,如集合類中的List,Map,HashMap,Set, 日期類Date,日曆類Calender, 而java.awt則封裝的是和圖形繪製相關的類,如Po

Android中的執行執行

執行緒與執行緒池 概括 執行緒分為主執行緒和子執行緒. 主執行緒主要是用來處理和介面相關的事情, 子執行緒主要是用來做耗時的操作,比如 載入遠端資料,資料庫操作等。 在android 中,處理直接使用 Thread以外。 android 還提供了很多類似執行緒的操作便於我們

java中執行執行的利弊(android適用)

介紹new Thread的弊端及Java四種執行緒池的使用,對Android同樣適用。本文是基礎篇,後面會分享下執行緒池一些高階功能。 1、new Thread的弊端 執行一個非同步任務你還只是如下new Thread嗎? new Thread(new Runnable(

Android執行執行

一.特殊的執行緒 1.AsynTask 底層用到了執行緒池,封裝了執行緒池和Handler,主要是為了方便開發者在子執行緒中更新UI 2.IntentService 內部採用HandlerThread來執行任務,當任務執行完畢後IntentService會自動退出,底層直

Android執行執行(一)

前言,學習安卓很久了,一直也沒有學部落格的習慣,下決心從今天開始要養成寫部落格總結學習經驗的好習慣! 一.Android中執行緒與執行緒池的簡介 在Android中執行緒主要可以分為兩大類:一個用於處理介面相關與使用者互動的執行緒-主執行緒;一個用於處理耗時任務-子執行緒

執行 技術點 目錄 1. 執行作用: 提升效能 1 2. 使用流程 1 3. 執行執行的監控 jvisual 1 4. 執行常用方法 2 5. 執行相關概念 2 5.1. 佇列

 池與執行緒池 技術點   目錄 1. 執行緒池作用:  提升效能 1 2. 使用流程 1 3. 執行緒與執行緒池的監控  jvisual 1 4. 執行緒常用方法 2 5. 執行緒池相關概念 2 5.1. 佇列 &n

c++11多執行執行

最近需要開發一個高效能運算庫,涉及到c++多執行緒的應用,上次做類似的事情已經是4年多以前了,印象中還頗有些麻煩。悔當初做了就算了,也沒想著留點記錄什麼的。這次又研究了一番,發現用上c++11特性之後,現在已經比較簡單了,在此記錄一下。   最簡單的多執行緒情況,不涉及公共變數,各個執行緒之間獨

執行執行

1.Callable和Runnable I    Callable定義的方法是call,而Runnable定義的方法是run。 II   Callable的call方法可以有返回值,而Runnable的run方法不能有返回值。 III  Callable的call方法可丟擲異常,而Runnable的ru

HTML5 Web Worker 多執行執行

筆者最近對專案進行優化,順帶就改了些東西,先把請求方式優化了,使用到了web worker。筆者發現目前還沒有太多深入對web worker的使用的文章,除了涉及到一些WebGL的文章,所以總結了這個文章,給大家參考參考。一下內容以預設你對web worker已經有了初步瞭解,不會講解基礎知

Android-Java-程序執行

 1.程序:什麼是程序:     Mac作業系統,Windows作業系統 ...... 等等,都是由多個程序來執行(系統程序,普通程序,等)     作業系統最小的控制單元是程序,一個應用就是一個程序      程序 全稱為:作業系統正在執行的應用程式     一個程序至少有一個或多個執行緒

python 多執行執行

原始地址 http://www.ibm.com/developerworks/cn/aix/library/au-threadingpython/ 資料學習:http://www.cnblogs.com/goodhacker/p/3359985.html 引言 對於

執行執行總結

先看幾個概念: 執行緒:程序中負責程式執行的執行單元。一個程序中至少有一個執行緒。 多執行緒:解決多工同時執行的需求,合理使用CPU資源。多執行緒的執行是根據CPU切換完成,如何切換由CPU決定,因此多執行緒執行具有不確定性。 執行緒池:基本思想還是一種物件池的思想,開闢

Android的程序執行(3)執行安全問題

當一個程式啟動的時候,系統會為程式建立一個名為main的執行緒。這個執行緒重要性在於它負責把事件分發給適合的使用者元件,這些事件包括繪製事件。並且這個執行緒也是你的程式與Android UI工具包中的元件(比如android.widget和android.view包中的元件

java多執行執行

1. 場景描述 以前多執行緒也常用,這次因需再頁面上用到多執行緒,如下圖,總結下,有需要的朋友可以參考下。 2. 解決方案 2.1 執行緒池概念 執行緒池官方定義不說了,通俗說下:池子的概念,事先(預定義)建立後,後續的執行緒可以直接從池子中拿,好處: (1)來建立執行緒比較消耗資源,不用重複建立; (2

Java併發程式設計(4):守護執行執行阻塞的四種情況

守護執行緒Java中有兩類執行緒:User Thread(使用者執行緒)、Daemon Thread(守護執行緒) 使用者執行緒即執行在前臺的執行緒,而守護執行緒是執行在後臺的執行緒。 守護執行緒作用是為其他前臺執行緒的執行提供便利服務,而且僅在普通、非守護執行緒仍然執行時才需要,比如垃圾回收執行緒就是一個

Java執行執行安全,開啟多執行及每執行迴圈10次對類進行輸出測試

最近看到執行緒問題,emmm~腦闊回想到計算機作業系統貌似又講,不過上課睡覺覺去啦哈哈哈,java課老師莫得講~ 然歸正傳,今對執行緒進行查閱及測試,做一下筆記,有錯之處還請指出,謝謝~上程式碼之前呢先說一哈前傳 執行緒是程序中的最小執行單位:    手機呢會有很多單獨

JAVA執行執行、程序程序間通訊

I.執行緒與執行緒間通訊 一、基本概念以及執行緒與程序之間的區別聯絡: 關於程序和執行緒,首先從定義上理解就有所不同 1、程序是什麼? 是具有一定獨立功能的程式、它是系統進行資源分配和排程的一個獨立單位,重點在系統排程和單獨的單位,也就是說程序是可以獨 立執行的一段程式。

C#中的多執行執行死鎖

多執行緒(英語:multithreading),是指從軟體或者硬體上實現多個執行緒併發執行的技術。具有多執行緒能力的計算機因有硬體支援而能夠在同一時間執行多於一個執行緒,進而提升整體處理效能。具有這種能力的系統包括對稱多處理機、多核心處理器以及晶片級多處理(Ch

Java併發程式設計之set集合的執行安全類知道

Java併發程式設計之-set集合的執行緒安全類 Java中set集合怎麼保證執行緒安全,這種方式你知道嗎? 在Java中set集合是 本篇是《凱哥(凱哥Java:kagejava)併發程式設計學習》系列之《併發集合系列》教程的第二篇: 本文主要內容:Set集合子類底層分別是什麼?基於底層為什麼set的子類可