Android 多線程

  • AsyncTask
  • HandlerThread
  • IntentService
  • android中的線程池

android 中的多線程主要通過Thread Handler 來完成,它提供了幾種形態:AsyncTask、HandlerThread、IntentService,下面一 一介紹。

1、AsyncTask

它是一種輕量級的異步任務類,可以在線程池中執行后臺任務,然后把執行的進度和最終結果傳遞給主線程并在主線程中更新UI。從實現上來說,AsyncTask封裝了Thread 和Handler,通過AsyncTask可以更加方便的執行后臺任務以及在主線程中處理UI,但是AsyncTask并不適合進行特別耗時的后臺任務,對于這些耗時的任務建議使用線程池。AsyncTask在使用過程中有條件限制,主要有如下幾點:
(1)AsyncTask類必須在主線程中加載。
因為AsyncTask里面有個一靜態的Handler對象,為了能夠將執行環境切換到主線程,這就要求Handler必須在主線程中創建,所以AsyncTask必須在主線程中進行類加載。
(2)AsyncTask的對象必須在主線程中創建。
(3)execute 方法必須在UI線程調用。
(4)一個AsyncTask對象只能執行一次,即只能調用一次execute方法,否則報運行時異常。
(5)在Android1.6之前,AsyncTask是串行執行任務的,Android1.6的時候AsyncTask開始使用線程池處理并行任務,但是從Android3.0開始,為了避免AsyncTask所帶來的并發錯誤,AsyncTask又采用一個線程串行執行任務。盡管如此,在Android3.0以及后續的版本中,我們仍然可以通過AsyncTask的executeOnExecutor方法來并行地執行任務。

2、HandlerThread

HandlerThread繼承了Thread,它是一種可以使用Handler的Thread,它的實現也很簡單,就是run方法中通過Looper.prepare()來 創建消息隊列,并通過Looper.loop()來開啟消息循環,這樣在實際使用中就允許在HandlerThread中創建Handler了。其run方法如下所示:

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

HandlerThread因為在內部創建了一個消息隊列,所以需要在外部通過Handler發送消息通知HandlerThread執行一個具體的任務,其應用場景如下:
1、構建一個后臺的Handler執行耗時操作

import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import org.json.JSONException;

import java.util.List;

/**
 * 描述 具備后臺線程和UI線程更新
 * 
 * @author chenjinyuan
 * @since 2013-12-2 上午9:45:00
 */
public abstract class BaseWorkerActivity extends BaseActivity {

    protected HandlerThread mHandlerThread;

    protected BackgroundHandler mBackgroundHandler;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mHandlerThread = new HandlerThread("activity worker:" + getClass().getSimpleName());
        mHandlerThread.start();
        mBackgroundHandler = new BackgroundHandler(mHandlerThread.getLooper());

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mBackgroundHandler != null && mBackgroundHandler.getLooper() != null) {
            mBackgroundHandler.getLooper().quit();
        }
    }

    /**
     * 處理后臺操作
     */
    protected abstract void handleBackgroundMessage(Message msg) throws JSONException;

    /**
     * 發送后臺操作
     * 
     * @param msg
     */
    protected void sendBackgroundMessage(Message msg) {
        if (mBackgroundHandler != null) {

            mBackgroundHandler.sendMessage(msg);
        }
    }

    /**
     * 發送后臺操作
     * 
     * @param what
     */
    protected void sendEmptyBackgroundMessage(int what) {
        if (mBackgroundHandler != null) {

            mBackgroundHandler.sendEmptyMessage(what);
        }
    }

    // 后臺Handler
    @SuppressLint("HandlerLeak")
    public class BackgroundHandler extends Handler {

        BackgroundHandler(Looper looper) {
            super(looper);
        }
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            try {
                handleBackgroundMessage(msg);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }

}

2、IntentService封裝了HandlerThread和Handler,這個在下一點會講到。
注意:HandlerThread的run是一個無限循環,因此當明確不需要HandlerThread時,可以通過它的quit或者quitSafely方法來終止線程的執行。

3、IntentService

IntentService是一種特殊的Service,他繼承了Service并且它是一個抽象類,因此必須創建它的子類才可以使用IntentService。IntentService封裝了HandlerThread和Handler,這點可以從他的onCreate();方法中看出來,如下所示:

@Override
public void onCreate() {   
 // TODO: It would be nice to have an option to hold a partial wakelock   
 // during processing, and to have a static startService(Context, Intent)   
 // method that would launch the service & hand off a wakelock.  
  super.onCreate();    
  HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");   
  thread.start();  
  mServiceLooper = thread.getLooper();   
  mServiceHandler = new ServiceHandler(mServiceLooper);
}

IntentService是在onStartCommand中處理每個后臺任務的Intent。在該方法中發送消息給ServiceHandler去處理,具體處理方法為:

@WorkerThreadprotected abstract void onHandleIntent(Intent intent);

是一個抽象方法,需要我們在子類中去實現。

4、android中的線程池

線程池的好處可以概括為一下三點:

  • 重用線程池中的線程,避免因為線程的創建和銷毀所帶來的性能開銷。
  • 能有效控制線程池的最大并發數,避免大量的線程之間因相互搶占系統資源而導致的阻塞現象。
  • 能夠對線程進行簡單的管理,并提供定時執行以及指定間隔循環執行等功能。

Android中線程池的概念來源于Java中的Executor,Executor是一個接口,真正的線程池實現為ThreadPoolExecutor。ThreadPoolExecutor提供了一系列參數來配置線程池,主要為4類,在介紹這四類線程池之前先了解一下ThreadPoolExecutor。
ThreadPoolExecutor常用的構造方法:

public ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) { 
   this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,threadFactory, defaultHandler);
}
corPoolSize

線程池的核心線程數,默認情況下,核心線程會在線程池中一直存活,即使他們處于閑置狀態。如果將ThreadPoolExecutor的allowCoreThreadTimeOut屬性設置為true,那么閑置的核心線程在等待新任務到來時會有超時策略,這個時間間隔有keepAliveTime所指定,當等待時間超過keepAliveTime所指定的時長后,核心線程就會被終止。

maximumPoolSize

線程池所能容納的最大線程數。

keepAliveTime

非核心線程閑置時的超時時長,超過這個時長,非核心線程就會被回收。當ThreadPoolExecutor的allowCoreThreadTimeOut屬性設置為true時,keepAliveTime同樣會作用于核心線程。

unit

用于指定keepAliveTime參數的時間單位,這是一個枚舉,常用的有TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分)等。

workQueue

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

threadFactory

線程工廠,用來創建新的線程。它是一個接口,且它只有一個方法:Thread newThread(Runnable r)。

ThreadPoolExecutor執行任務時大致遵循如下規則:

(1) 如果線程池中的線程數量未達到核心線程的數量,那么會直接啟動一個核心線程來執行。
(2) 如果線程池中的線程數已經達到或者超過核心線程數,那么任務會被插入到任務隊列中排隊等待執行。
(3)如果在步驟2中無法將任務插入到任務隊列中,這往往是由于任務隊列已滿,這時候如果線程池的線程數量沒有達到規定的最大值,那么會立即啟動一個非核心線程來執行任務。
(4) 如果步驟3中線程數量已經達到線程池規定的最大值,那么就拒絕執行此任務,ThreadPoolExecutor會調用RejectedExecutionHandler的rejectedExecution方法來通知調用者。

線程池的分類
Executors 中給我們提供了好幾種線程池,他們都是通過Executors的newCacheThreadPool方法來創建的,常見的有以下四種:

1、FixedThreadPool

它是一種線程數量固定的線程池,它只有核心線程,并且當這些線程處在空閑狀態時它不會被回收,除非線程池被關閉了,另外,任務隊列也是沒有大小限制的。

public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {    
          return new ThreadPoolExecutor(nThreads,nThreads,0L,TimeUnit.MILLISECONDS,  
                    new LinkedBlockingQueue<Runnable>(),    threadFactory);
}
2、CachedThreadPool

它是一種線程數量不定的線程池,他只有非核心線程,并且其最大線程數為Integer.MAX_VALUE。實際上相當于最大線程數可以任意大。當線程池中的線程都處于活動狀態時它會創建新的線程來執行,否則會利用閑置線程來處理任務,閑置線程 超時時間為60s,這時它的任務隊列 相當于一個空集合。這類線程池適合執行大量的耗時較少的任務。

public static ExecutorService newCachedThreadPool() {  
  return new ThreadPoolExecutor(0, Integer.MAX_VALUE,   60L, TimeUnit.SECONDS,
  new SynchronousQueue<Runnable>());
}
3、ScheduledThreadPool

它的核心線程數是固定的,而非核心線程數是沒有限制的,并且當非核心線程閑置時會被立即回收。這類線程主要用來執行定時任務和具有固定周期的重復任務。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { 
   return new ScheduledThreadPoolExecutor(corePoolSize);
}

public ScheduledThreadPoolExecutor(int corePoolSize) {    
super(corePoolSize, Integer.MAX_VALUE,  10, MILLISECONDS,      
    new DelayedWorkQueue());
}
4、SingleThreadExecutor

這類線程池內部只有一個核心線程,它確保所有任務都在同一線程中按順序執行。SingleThreadExecutor的意義在于統一所有的外界任務到同一個線程中,這使得在這些任務之間不需要處理線程同步的問題。

public static ExecutorService newSingleThreadExecutor() {  
  return new FinalizableDelegatedExecutorService  (new ThreadPoolExecutor(1, 1,  
  0L,TimeUnit.MILLISECONDS,  new LinkedBlockingQueue<Runnable>()));
}
                                  `以上資料參考《Android藝術開發探索》`
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 簡介 1. 線程分類 主線程(UI線程) : 處理和界面相關的事情. 子線程 : 處理耗時操作. Android中...
    王世軍Steven閱讀 929評論 0 2
  • Android 多線程的可以歸納為兩種情況:1、將任務從工作線程拋到主線程;2、將任務從主線程拋到工作線程; 一、...
    秀花123閱讀 1,354評論 1 7
  • Android中的線程 線程,在Android中是非常重要的,主線程處理UI界面,子線程處理耗時操作。如果在主線程...
    shenhuniurou閱讀 812評論 0 3
  • 消息機制 處理消息的手段--Handler,Looper與MessageQueue =tips:= 子線程無法更新...
    hloong閱讀 857評論 1 2
  • 從用途上來說,線程分為主線程和子線程,主線程主要處理和界面相關的事情,子線程則往往用于執行耗時操作。 除了Thre...
    小柏不是大白閱讀 645評論 0 3