我們知道線程是CPU調度的最小單位。在Android中主線程是不能夠做耗時操作的,子線程是不能夠更新UI的。在Android中,除了Thread外,扮演線程的角色有很多,如AsyncTask,IntentService和HandlerThread等等。由於內容過多,所以將分為上下兩部分,第一部分主要和大家談談Android中的線程,以及在Android中的常用的線程池。第二部分我們一起來了解一下AsyncTask的使用和工作原理。
1、HandlerThread
HandlerThread是Thread的子類,它是一種可以使用Handler的Thread,它的實現比較簡單。我們來看看它的源碼:
1 package android.os; 2 3 public class HandlerThread extends Thread { 4 int mPriority; 5 int mTid = -1; 6 Looper mLooper; 7 8 public HandlerThread(String name) { 9 super(name); 10 mPriority = Process.THREAD_PRIORITY_DEFAULT; 11 } 12 13 14 public HandlerThread(String name, int priority) { 15 super(name); 16 mPriority = priority; 17 } 18 19 20 protected void onLooperPrepared() { 21 } 22 23 24 25 @Override 26 public void run() { 27 mTid = Process.myTid(); 28 Looper.prepare(); 29 synchronized (this) { 30 mLooper = Looper.myLooper(); 31 notifyAll(); 32 } 33 Process.setThreadPriority(mPriority); 34 onLooperPrepared(); 35 Looper.loop(); 36 mTid = -1; 37 } 38 39 40 41 public Looper getLooper() { 42 if (!isAlive()) { 43 return null; 44 } 45 46 // If the thread has been started, wait until the looper has been created. 47 synchronized (this) { 48 while (isAlive() && mLooper == null) { 49 try { 50 wait(); 51 } catch (InterruptedException e) { 52 } 53 } 54 } 55 return mLooper; 56 } 57 58 59 60 public boolean quit() { 61 Looper looper = getLooper(); 62 if (looper != null) { 63 looper.quit(); 64 return true; 65 } 66 return false; 67 } 68 69 70 71 72 73 public boolean quitSafely() { 74 Looper looper = getLooper(); 75 if (looper != null) { 76 looper.quitSafely(); 77 return true; 78 } 79 return false; 80 } 81 82 83 84 85 public int getThreadId() { 86 return mTid; 87 } 88 }
為了讓大家看清楚,我們源碼的一些英文注釋干掉了,現在就很清晰了。整個類中,除了構造方法和對外提供幾個public方法以外,就剩一個方法了run()。從它的實現來看,和普通的Thread實現沒有什么區別。都是在run()方法中執行耗時操作。不過,HandlerThread內部創建了消息隊列,並且run()方法是一個無限循環的方法,當我們不需要HandlerThread的時候,我們可以調用quitSafely()或者quit()方法來結束這個線程。這是比較方便的。
2、IntentService
IntentService是一種特殊的Service,它是Service的子類,並且它是一個抽象類,所以必須創建它的子類才可以使用Intent Service。Intent Service可用於執行后台的耗時任務,當任務執行完畢,它會自己結束,不需要開發着手動結束它。這里需要注意一個問題,Intentservice內置有線程,但是它還是屬於Service,所以它的優先級會比線程高很多,所以不容易被系統殺死。所以比較合適去執行一些優先級比較高的任務。看看它的源碼:
1 package android.app; 2 3 import android.annotation.WorkerThread; 4 import android.annotation.Nullable; 5 import android.content.Intent; 6 import android.os.Handler; 7 import android.os.HandlerThread; 8 import android.os.IBinder; 9 import android.os.Looper; 10 import android.os.Message; 11 12 13 14 public abstract class IntentService extends Service { 15 private volatile Looper mServiceLooper; 16 private volatile ServiceHandler mServiceHandler; 17 private String mName; 18 private boolean mRedelivery; 19 20 21 22 private final class ServiceHandler extends Handler { 23 public ServiceHandler(Looper looper) { 24 super(looper); 25 } 26 27 28 29 @Override 30 public void handleMessage(Message msg) { 31 onHandleIntent((Intent)msg.obj); 32 stopSelf(msg.arg1); 33 } 34 } 35 36 37 38 39 public IntentService(String name) { 40 super(); 41 mName = name; 42 } 43 44 45 46 47 public void setIntentRedelivery(boolean enabled) { 48 mRedelivery = enabled; 49 } 50 51 @Override 52 public void onCreate() { 53 // TODO: It would be nice to have an option to hold a partial wakelock 54 // during processing, and to have a static startService(Context, Intent) 55 // method that would launch the service & hand off a wakelock. 56 57 super.onCreate(); 58 HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); 59 thread.start(); 60 61 mServiceLooper = thread.getLooper(); 62 mServiceHandler = new ServiceHandler(mServiceLooper); 63 } 64 65 66 67 68 @Override 69 public void onStart(@Nullable Intent intent, int startId) { 70 Message msg = mServiceHandler.obtainMessage(); 71 msg.arg1 = startId; 72 msg.obj = intent; 73 mServiceHandler.sendMessage(msg); 74 } 75 76 77 78 79 @Override 80 public int onStartCommand(@Nullable Intent intent, int flags, int startId) { 81 onStart(intent, startId); 82 return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; 83 } 84 85 86 87 88 @Override 89 public void onDestroy() { 90 mServiceLooper.quit(); 91 } 92 93 94 95 96 public IBinder onBind(Intent intent) { 97 return null; 98 } 99 100 101 102 103 @WorkerThread 104 protected abstract void onHandleIntent(@Nullable Intent intent); 105 }
這里就很簡單了,這些方法對於經常使用Service的朋友來說,就很熟悉了。大家看onCreate()方法。沒錯IntentService就是封裝了HandlerThread和Handler。
當我們啟動IntentService是onCreate(),方法將會被調用,然后就會創建HandlerThread和ServiceHandler。而onStartCommand()方法又調用了onStart()方法,從onStart()方法可以看出IntentService 僅僅是通過ServiceHandler來發一個消息,這個消息會在HandlerThread中被處理掉。
大家看這個onStart()方法,將intent作為消息傳遞給onHandleIntent,這個intent通常是我們傳遞進來的數據。而onHandleIntent就是通過這個intent來區別具體的后台任務的。
好了,AsyncTask的使用和工作原理。我們會在下一章在說。下面我們看看線程池吧。
不知道大家有沒有遇到過這種情況。我們在寫項目,遇到耗時操作的時候,怎么辦呢,是不是new Thread().start,那這樣的話,整個項目中得new多少個Thread。這種明顯是很浪費性能。畢竟線程也是好資源的嘛。那么有沒有一種可以方法對線程進行復用呢?答案就是線程池。
先說一下線程池的好處:
1、重用線程池中的線程,避免因為線程的創建和銷毀帶來的性能開銷。
2、能有效的控制線程池中的線程並發數,避免大量線程之間因為互相搶占資源而導致的阻塞現象。
3、能夠對線程進行簡單的管理,並提供定時執行以及指定間隔循環執行等功能。
ThreadPoolExecutor
Android中的線程池概念是來源於java中Executor,Executor是一個空的接口,真正的線程池實現ThreadPoolExecutor。
1 public ThreadPoolExecutor(int corePoolSize, 2 int maximumPoolSize, 3 long keepAliveTime, 4 TimeUnit unit, 5 BlockingQueue<Runnable> workQueue, 6 ThreadFactory threadFactory) { 7 this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, 8 threadFactory, defaultHandler); 9 }
簡單介紹一下ThreadPoolExcutor各個參數的含義
corePoolSize:線程池的核心線程數,默認情況下,核心線程會在線程池中一直存活,即使他們處於閑置狀態。當我們把ThreadPoolExecutor中的allowCoreThreadTimeOut屬性設置為true,那么閑置的核心線程在等待新任務的時候,如果時間超過keepAliveTime所設置的時間,核心線程將會被回收。
maximumPoolSize:設置最大線程池能夠容納的最大線程數,當線程池中的線程達到這個數以后,新任務將會被阻塞。
keepAliveTime:非核心線程數閑置的時間。
unit:指定keepAliveTime參數的時間單位。
workQueue:線程池中的任務隊列。
threadFactory:線程工廠,為線程池提供創建新線程的功能。
線程池的分類
Android中常見的線程池有四種,FixedThreadPool、CachedThreadPool、ScheduledThreadPool、SingleThreadExecutor。
FixedThreadPool
FixedThreadPool線程池是通過Executors的new FixedThreadPool方法來創建。它的特點是該線程池中的線程數量是固定的。即使線程處於閑置的狀態,它們也不會被回收,除非線程池被關閉。當所有的線程都處於活躍狀態的時候,新任務就處於隊列中等待線程來處理。注意,FixedThreadPool只有核心線程,沒有非核心線程。
1 public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { 2 return new ThreadPoolExecutor(nThreads, nThreads, 3 0L, TimeUnit.MILLISECONDS, 4 new LinkedBlockingQueue<Runnable>(), 5 threadFactory); 6 }
CachedThreadPool
CachedThreadPool線程池是通過Executors的newCachedThreadPool進行創建的。它是一種線程數目不固定的線程池,它沒有核心線程,只有非核心線程,當線程池中的線程都處於活躍狀態,就會創建新的線程來處理新的任務。否則就會利用閑置的線程來處理新的任務。線程池中的線程都有超時機制,這個超時機制時長是60s,超過這個時間,閑置的線程就會被回收。這種線程池適合處理大量並且耗時較少的任務。這里得說一下,CachedThreadPool的任務隊列,基本都是空的。
1 public static ExecutorService newCachedThreadPool() { 2 return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 3 60L, TimeUnit.SECONDS, 4 new SynchronousQueue<Runnable>()); 5 }
ScheduledThreadPool
ScheduledThreadPool線程池是通過Executors的newScheduledThreadPool進行創建的,它的核心線程是固定的,但是非核心線程數是不固定的,並且當非核心線程一處於空閑狀態,就立即被回收。這種線程適合執行定時任務和具有固定周期的重復任務。
1 public static ScheduledExecutorService newScheduledThreadPool( 2 int corePoolSize, ThreadFactory threadFactory) { 3 return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); 4 } 5 6 7 public ScheduledThreadPoolExecutor(int corePoolSize, 8 ThreadFactory threadFactory) { 9 super(corePoolSize, Integer.MAX_VALUE, 10 DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, 11 new DelayedWorkQueue(), threadFactory); 12 }
SingleThreadExecutor
SingleThreadExecutor線程池是通過Executors的newSingleThreadExecutor方法來創建的,這類線程池中只有一個核心線程,也沒有非核心線程,這就確保了所有任務能夠在同一個線程並且按照順序來執行,這樣就不需要考慮線程同步的問題。
1 public static ExecutorService newSingleThreadExecutor() { 2 3 return new FinalizableDelegatedExecutorService 4 5 (new ThreadPoolExecutor(1, 1, 6 7 0L, TimeUnit.MILLISECONDS, 8 9 new LinkedBlockingQueue<Runnable>())); 10 11 }
好了,寫了這么多,真特么累,下部分就和大家分享一下AsyncTask的 工作原理。