線程在Android中是一個很重要的概念,從用途上來講,線程分爲主線程和子線程,主線程主要處理和界面相關的事情,而子線程則每每用於執行耗時操做。因爲Android的特性,若是在主線程中執行耗時操做那麼就會致使程序沒法及時地響應,所以耗時操做必須放在子線程中去執行。android
在操做系統中,線程是操做系統調度的最小單元,同時線程又是一種受限的系統資源,即線程不可能無限制的產生,而且線程的建立和銷燬都會有相應的開銷。檔系統中存在大量的線程時,系統會經過時間片輪轉的方式調度每一個線程,所以線程不可能作到絕對的並行,除非線程數量小於等於CPU核心數,通常來講這是不可能的。正確的作法是採用線程池,一個線程池會緩存必定數量的線程,經過線程池就能夠避免由於頻繁建立和銷燬線程所帶來的系統開銷。編程
Android沿用了Java的線程模型,其中的線程也分爲主線程和子線程,其中主線程也叫UI線程。主線程的做用是運行四大組件以及處理它們和用戶的交互,而子線程的做用則是執行耗時任務,好比網絡請求、I/O操做等。從Android3.0開始系統要求網絡訪問必須在子線程中進行,不然網絡訪問將會失敗並拋出NetworkOnMainThreadException這個異常,這樣作事爲了不主線程因爲耗時操做所阻塞而出現ANR異常。緩存
除了傳統的Thread線程外,Android還提供了AsyncTask、HandlerTask以及IntentService,這三者的底層實現也是線程,但它們具備特殊的表現形式,同時在使用上也各有優缺點。網絡
AsyncTask是一種輕量級的異步任務類,它能夠在線程池中執行後臺任務,而後把執行的進度和最終結果傳遞給主線程並在主線程上更新UI。是實現上來講,AsyncTask封裝了Thread和Handler,經過AsyncTask能夠更加方便地執行後臺任務以及在主線程中訪問UI,可是AsyncTask並不適合進行特別耗時的任務,對應特別耗時的任務來講,建議使用線程池。併發
AsyncTask是一個抽象的泛型類,它提供了Params、Progress和Result這三個泛型參數,其中Params表示輸入參數的類型,Progress表示後臺任務的執行進度的類型,而Result則表示後臺任務返回結果的類型,若是AsyncTask確實不須要傳遞具體的參數,那麼這三個泛型能夠用Void來代替。聲明以下:異步
public abstract class AsyncTask<Params,Progress,Result>
AsyncTask提供了4個核心方法,它們的含義以下圖所示ide
onPreExecute(),在主線程中執行,在異步任務執行以前會調用此方法,通常能夠用於作一些準備工做。oop
doInBackground(Params...params),在線程池中執行,用於執行異步任務,params表示異步任務的輸入參數。在該方法中能夠經過調用publishProgress方法來更新任務的進度,由於publishProgress會調用onProgressUpdate方法。post
onProgressUpdate(Progress...values),在主線程中執行,當後臺任務的執行進度發生改變時此方法會被調用。性能
onPostExecute(Result result),在主線程中執行,在異步任務執行以後,次方法會被調用,其中result參數是後臺任務的返回值,即doInBackground的返回值。
上述方法中,onPreExecute先執行,而後是doInBackground,最後纔是onPostExecute。此外AsyncTask還提供了onCancelled()方法,它一樣在主線程中執行,當異步任務被取消時,onCancelled()方法會被調用,這個時候onPostExecute則不會被調用。
下面代碼爲AsyncTask的一個應用實例:
private class LoadRecordTask extends AsyncTask<Object, VideoInfo, List<VideoInfo>> { @Override protected void onPreExecute() { // TODO Auto-generated method stub super.onPreExecute(); mDescLoad.setVisibility(View.VISIBLE); mDescLoad.setText(R.string.refreshing); mVideoRecords.setEnabled(false); } @Override protected List<VideoInfo> doInBackground(Object... params) { // TODO Auto-generated method stub videoInfos = (ArrayList<VideoInfo>) MediaContentResolverUtils .getVideoInfoList(RecordVideoActivity.this); mVideoThumbnailMap = (HashMap<String, String>) mVideoThumbnailDao .findAllToMap(); if (videoInfos == null || videoInfos.size() == 0) { return videoInfos; } // 沒有縮略圖 獲取縮略圖 for (VideoInfo info : videoInfos) { String md5Name = Md5Utils.encode(info.getFileTitle()); if (!mVideoThumbnailMap.containsKey(md5Name)) { //數據處理 } publishProgress(info); if (isCancelled()) { //異步任務取消時會調用 break; } } return videoInfos; } @Override protected void onProgressUpdate(VideoInfo... values) { // TODO Auto-generated method stub super.onProgressUpdate(values); for (VideoInfo info : values) { //UI更新進度 } } @Override protected void onPostExecute(List<VideoInfo> result) { //取得後臺任務的結果,更新UI } /** * 運行在UI線程,調用cancel()方法後觸發,在doInBackground()方法結束後執行 */ @Override protected void onCancelled(List<VideoInfo> result) { // TODO Auto-generated method stub super.onCancelled(result); } }
運行和取消該任務的代碼以下:
mLoadRecordTask = new LoadRecordTask(); mLoadRecordTask.execute(); mLoadRecordTask.cancel(true); //結束任務
AsyncTask的類必須在主線程中加載
AsyncTask的對象必須在主線程中建立
execute方法必須在UI線程調用
不要在程序中直接調用onPreExecute()、onPostExecute()、doInBackgroud()和onProgressUpdate()
一個AsyncTask對象只能執行一次,即只能調用一次execute方法,不然會報運行時異常
在Android1.6以前,AsyncTask是串行執行任務的,Android1.6的時候AsyncTask開始採用線程池裏處理並行任務,但從Android3.0開始,爲了不AsyncTask所帶來的併發錯誤,AsyncTask又採用一個線程來串行執行任務。儘管如此,在Android3.0及之後版本中,咱們仍然能夠經過AsyncTask的executeOnExecutor方法(不能向下兼容)來並行的執行任務
咱們從AsyncTask的execute方法開始分析,execute方法又會調用ecuteOnExecutor方法,它們的實現以下:
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; }
上述代碼中,sDefaultExecutor其實是一個串行的線程池,一個進程中全部的AsyncTask所有在這個串行的線程池中排隊執行。在executeOnExecutor方法中,AsyncTask的onPreExecute()最早執行,而後線程池開始執行。下面分析線程池的執行過程,以下所示:
public AsyncTask() { mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked return postResult(doInBackground(mParams)); } }; //將AsyncTask的Params參數封裝到FutureTask對象中,FutureTask的run方法會調用mWorker的call方法 mFuture = new FutureTask<Result>(mWorker) { @Override protected void done() { try { postResultIfNotInvoked(get()); } catch (InterruptedException e) { android.util.Log.w(LOG_TAG, e); } catch (ExecutionException e) { throw new RuntimeException("An error occured while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } } }; } private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); //CPU核心數 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; //空閒線程的超時時間爲1秒 public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; //實現一個線程池 private static class SerialExecutor implements Executor { final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); Runnable mActive; //線程同步 public synchronized void execute(final Runnable r) { //將任務r插入mTasks任務隊列中 mTasks.offer(new Runnable() { public void run() { try { r.run(); //執行任務 } finally { scheduleNext(); //繼續執行下一個任務 } } }); //沒有真正活動的AsyncTask時調用 if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); //真正執行任務 } } }
從SerialExecutor的實現能夠分析AsyncTask的排隊執行狀況。首先系統會將AsyncTask的Params參數封裝到FutureTask對象中,FutureTask是一個併發類,在這裏它充當了Runnable的做用(FutureTask實現了Runnable方法)。接着這個FutureTask即mFuture會交給SerialExecutor的execute方法去處理。SerialExecutor的execute方法首先會把FutureTask對象添加到任務隊列mTasks中,若是當前沒有正在活動的AsyncTask任務,那麼就會調用SerialExecutor的scheduleNext方法來執行下一個AsyncTask任務,不然等待當前AsyncTask任務完成再繼續執行新的AsyncTask任務,直到全部的AsyncTask任務執行完畢。從這能夠看出,AsyncTask是串行執行任務的
AsyncTask中有兩個線程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一個Handler(InternalHandler),其中線程池SerialExecutor用於執行任務的排隊,線程池THREAD_POOL_EXECUTOR用於真正地執行AsyncTask任務,InternalHandler用於將執行環境從線程池切換到主線程。在AsyncTask的構造方法中有以下這麼一段代碼,因爲FutureTask的run方法調用mWorker的call方法,所以mWorker的call方法最終會在線程池中執行。
public AsyncTask() { mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); //表示當前任務以及調用過了 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked return postResult(doInBackground(mParams)); //執行doInBackground方法 } }; //將AsyncTask的Params參數封裝到FutureTask對象中,FutureTask的run方法會調用mWorker的call方法 mFuture = new FutureTask<Result>(mWorker) { @Override protected void done() { try { postResultIfNotInvoked(get()); } catch (InterruptedException e) { android.util.Log.w(LOG_TAG, e); } catch (ExecutionException e) { throw new RuntimeException("An error occured while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } } }; }
在mWorker的call方法中,首先將mTaskInvoked設爲true,表示當前任務以及被調用了,而後執行AsyncTask的doInBackground方法,接着將其返回值傳遞給postResult方法,它的實現以下:
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }
在上面的代碼中,postResult方法會經過sHandler發送一個MESSAGE_POST_RESULT的消息,這個sHandler的定義以下所示:
private static InternalHandler sHandler; private static Handler getHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { sHandler = new InternalHandler(); } return sHandler; } } 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這個對象必須在主線程中建立。因爲靜態成員會在加載類的時候進行初始化,所以這就變相要求AsyncTask的類必須在主線程中加載,不然同一進程中的AsyncTask都將沒法正常工做。sHandler收到sHandlerMESSAGE_POST_PROGRESS會調用onProgressUpdate方法更新進度,收到MESSAGE_POST_RESULT這個消息後會調用AsyncTask的finish方法,以下
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
AsyncTask的finish方法會判斷AsyncTask是否取消執行了,是則調用onCancelled方法,不然調用onPostExecute(result),此時doInBackground的返回結果會傳遞給onPostExecute方法,最後將任務狀態mStatus置爲完成。至此AsyncTask的整個過程就分析完成了。
經過分析AsyncTask的源碼,能夠進一步肯定,從Android3.0開始,默認狀況下AsyncTask的確是串行執行。咱們仍然能夠經過AsyncTask的executeOnExecutor方法(不能向下兼容)來並行的執行任務。
HandlerThread繼承了Thread,它是一種可使用Handler的Thread,它的實現也很簡單,就是在run方法中經過Looper.prepare()來建立消息隊列,並經過Looper.loop()來開啓消息循環,這樣在實際的使用中就容許HandlerThread中建立Handler。HandlerThread的run方法以下所示:
public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }
從HandlerThread的實現來看,它和普通的Thread有顯著的不一樣之處。普通Thread主要同於run方法中執行一個耗時任務,而HandlerThread在內部建立了消息隊列,外界須要經過Handler的消息方式來通知HandlerThread執行一個具體任務。HandlerThread是個頗有用的類,它在Android中的一個具體的使用場景是IntentService。因爲HandlerThread的run方法是一個無限循環,所以當明確不須要再使用HandlerThread時,能夠經過它的quit或者quitSafely方法來終止線程的執行,這是一個好的編程習慣。示例代碼以下:
public class HandlerThreadDemo extends Activity { private Looper mLooper; private MyHandlerThread mHandlerThread; private TextView mInfoTxt; private Handler mHandler; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_thread); mInfoTxt = (TextView) findViewById(R.id.tv_info); mHandlerThread = new MyHandlerThread("mHandlerThread"); mHandlerThread.start(); //先start mLooper = mHandlerThread.getLooper(); //註冊到Handler,經過Handler發送消息 mHandler = new Handler(mLooper,mHandlerThread); } public void click(View view) { mHandler.sendEmptyMessage(1); } private class MyHandlerThread extends HandlerThread implements Callback { public MyHandlerThread(String name) { super(name); // TODO Auto-generated constructor stub } @Override public boolean handleMessage(Message msg) { // TODO Auto-generated method stub if (msg.what == 1) { System.out.println("mHandlerThread"); mInfoTxt.setText("mHandlerThread"); } return true; } } }
IntentService是一種特殊的Service,它繼承了Service而且它是一個抽象類,所以必須建立它的子類才能使用IntentService。IntentService可用於執行後臺耗時的後臺,當任務執行後它會自動中止,同時因爲IntentService是服務的緣由,這致使它的優先級比單純的線程要高不少,因此IntentService比較適合執行一些高優先級的後臺任務,由於它的優先級高不容易被系統殺死。在實現上,IntentService封裝了HandlerThread和Handler,這一點能夠在它的onCreate方法中看出來,以下所示。
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被第一次啓動時,它的onCreate方法會被調用,onCreate方法會建立一個HandlerThread,而後使用它的Looper來構造一個Handler對象mServiceHandler,這樣經過mServiceHandler發送的消息最終都會在HandlerThread中執行,從這個角度來看,IntentService也能夠用於執行後臺任務。每次啓動IntentService,它的onStartCommand方法就會調用一次,IntentService在onStartCommand中處理每一個後臺任務的Intent。下面看一下onStartCommand方法是如何處理外界Intent的,onStartCommand調用了onStart,onStart方法的實現以下所示:
public void onStart(Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); }
能夠看出,IntentService僅僅是經過mServiceHandler發送了一個消息,這個消息會在HandlerThread中去處理。mServiceHandler收到消息後,會將Intent對象對象傳遞給onHandleIntent方法去處理。注意這個Intent對象的內容和外界的startService(intent)中的intent的內容是徹底一致的,經過這個Intent對象便可解析出外界啓動IntentService時所傳遞的參數,經過這些參數就能夠區分具體的後臺任務,這樣在onHandleIntent方法中就能夠對不一樣的後臺任務作處理了。當onHandleIntent方法執行結束後,IntentService會經過stopSelf(int startId)來嘗試中止服務。這裏之因此採用stopSelf(int startId)而不是stopSelf()來中止服務,是由於stopSelf()會馬上中止服務,而這個時候還可能有其餘消息未處理,stopSelf(int startId)則會等待全部的消息都處理完畢後才終止服務。通常來講,stopSelf(int startId)在嘗試中止服務以前會判斷最近啓動服務的次數是否和startId相等,若是相等就馬上中止服務,不相等則不中止服務,這個策略能夠從AMS的stopServiceToken方法的實現中找到依據。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參數中區分具體的任務並執行這些任務。若是目前只存在一個後臺任務,那麼onHandleIntent(Intent)方法執行完這個任務後,stopSelf(int startId)就會直接中止服務;若是目前存在多個後臺任務,那麼當onHandleIntent方法執行完最後一個任務時,stopSelf(int startId)纔會直接中止服務。另外,因爲沒執行一個後臺任務就必須啓動一次IntentService,而IntentService內部則經過消息的方式向HandlerThread請求執行任務,Handler中的Looper是順序處理消息的,這就意味着IntentService也是順序執行後臺任務,當有多個後臺任務同時存在時,這些後臺任務會按照外界發起的順序排隊執行。
下面經過一個示例來講明IntentService的工做方式,首先派生一個IntentService的子類,它的實現以下所示:
public class LocalIntentService extends IntentService { public LocalIntentService() { super("LocalIntentService"); // TODO Auto-generated constructor stub } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub System.out.println("onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override protected void onHandleIntent(Intent intent) { // TODO Auto-generated method stub String action = intent.getStringExtra("task"); System.out.println("action: " + action); SystemClock.sleep(3000); //休眠模擬耗時的後臺任務 if (action.equals("task1")) { System.out.println("handle action: " + action); } if (action.equals("task2")) { System.out.println("handle action: " + action); } if (action.equals("task3")) { System.out.println("handle action: " + action); } } @Override public void onDestroy() { // TODO Auto-generated method stub System.out.println("onDestroy"); super.onDestroy(); } }
LocalIntentService實現完成之後,就能夠在外界請求執行後臺任務了,下面在Activity中發起3個後臺任務的請求,以下所示:
Intent service = new Intent(this, LocalIntentService.class); service.putExtra("task", "task1"); startService(service); service.putExtra("task", "task2"); startService(service); service.putExtra("task", "task3"); startService(service);
運行程序,觀察日記以下
22:14:19.407: I/System.out(16384): onStartCommand 01-08 22:14:19.407: I/System.out(16384): action: task1 01-08 22:14:19.407: I/System.out(16384): onStartCommand 01-08 22:14:19.408: I/System.out(16384): onStartCommand 01-08 22:14:22.407: I/System.out(16384): handle action: task1 01-08 22:14:22.409: I/System.out(16384): action: task2 01-08 22:14:25.410: I/System.out(16384): handle action: task2 01-08 22:14:25.418: I/System.out(16384): action: task3 01-08 22:14:28.418: I/System.out(16384): handle action: task3 01-08 22:14:28.429: I/System.out(16384): onDestroy
從日誌能夠看出,三個後臺任務是排隊執行的,它們的執行順序就是它們發起請求對的順序。當task3執行完畢後,LocalIntentService才真正地中止,執行了onDestroy方法。
線程池的有點主要有三點:
重用線程池中的線程,避免由於線程的建立和銷燬所帶來的性能開銷
能有效控制線程池的最大併發數,避免大量的線程之間因互相搶佔系統資源而致使的阻塞現象。
可以對線程進行簡單的管理,並提供定時執行以及指定間隔循環執行等功能。
Android中的線程池概念來源於Java中的Executor,Executor是一個接口,真正的線程池的實現爲ThreadPoolExecutor。ThreadPoolExecutor提供了一系列參數來配置線程池,經過不一樣的參數能夠建立不一樣的線程池。因爲Android中的線程池都是直接或者間接經過配置ThreadPoolExecutor來實現的,所以須要先介紹ThreadPoolExecutor。
ThreadPoolExecutor是線程池的真正實現,它的構造方法提供了一系列參數來配置線程池,下面介紹ThreadPoolExecutor的構造方法中各個參數的含義,這些參數將會直接影響到線程池的功能特性,下面是ThreadPoolExecutor的一個比較經常使用的構造方法。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) { }
corePoolSize
線程池的核心線程數,默認狀況下,核心線程會在線程池中一直存活,即便他們處於閒置狀態。若是將ThreadPoolExecutor的allowCoreThreadTimeout屬性設置爲true,那麼閒置的核心線程在等待新任務到來會有超時策略,這個時間間隔由keepAliveTime所指定,當等待時間超時keepAliveTime所指定的時長後,核心線程會被終止。
maximumPoolSize
線程池所能容納的最大線程數,當活動線程達到這個數值後,後續的新任務將會被阻塞。
keepAliveTime
非核心線程閒置時的超時時長,超過這個時間,非核心線程就會被收回。當ThreadPoolExecutor的allowCoreThreadTimeout屬性設置爲true時,keepAliveTime一樣會做用於核心線程。
unit
用於指定keepAliveTime參數的時間單位,這是一個枚舉,經常使用的有TimeUnit.MILLISECONDS;TimeUnit.SECONDS;TimeUnit.MINUTES等
workQueue
線程池的任務隊列,經過線程池的execute方法提交的Runnable對象會存儲在這個參數中。
ThreadFactory
線程工廠,爲線程池提供建立新線程的功能。ThreadFactory是一個接口,它只有一個方法:Thread newThread(Runnable r);
除上面的這些主要的參數外,ThreadPoolExecutor還有一個不經常使用的參數RejectedExecutionHandler。當線程池沒法執行新的任務時,這多是因爲任務隊列已滿或者是沒法成功執行任務,這個時候ThreadPoolExecutor回調用RejectedExecutionHandler的rejectedExecution(Runnable r, ThreadPoolExecutor executor)方法來通知調用者,默認狀況下rejectedExecution會直接拋出一個RejectedExecutionException的運行時異常。ThreadPoolExecutor爲RejectedExectutionHandler提供了幾個可選值:CallerRunsPolicy、AbortPolicy、DiscardPolicy、DiscardOldestPolicy,其中AbortPolicy是默認值,可是RejectedExecutionHandler這個參數不經常使用。
ThreadPoolExecutor執行任務時大體遵循以下規則:
若是線程池中的線程數量未達到核心線程的數量,那麼會直接啓動一個核心線程來執行任務
若是線程池中的線程數量已經達到或超過核心線程的數量,那麼任務會被插入到任務隊列中排隊等待執行。
若是在步驟2中沒法將任務插入到任務隊列中,這每每是因爲任務隊列已滿,這個時候若是線程數量未達到線程池規定的最大值,那麼會馬上啓動一個非核心線程來執行任務。
若是步驟3中線程數量已經達到線程池中規定的最大值,那麼就拒絕執行此任務,ThreadPoolExecutor會調用RejectedExecutionHandler的rejectedExecution方法來通知調用者。
ThreadPoolExecutor的參數配置在AsyncTask中有明顯的體現,下面是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; 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); /** * An {@link Executor} that can be used to execute tasks in parallel. */ public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
AsyncTask線程池配置後的規格以下:
核心線程數等於CPU核心數+1
線程池的最大線程數爲CPU的核心數的2倍 + 1
核心線程無超時機制,非核心線程在閒置時的超時時間爲1秒
任務隊列的容量爲128
FixedThreadPool
經過Executors的newFixedThreadPool方法來建立。它是一種線程數量固定的線程池,當線程處於空閒狀態時,它們並不會被收回,除非線程池關閉了。當全部的線程都處於活動狀態時,新任務都會處於等待狀態,直到有線程空閒出來。因爲FixedThreadPool只有核心線程而且這些核心線程都不會被回收,這意味着它可以更加快速的響應外界的請求。實現以下,能夠發現FixedThreadPool中只有核心線程而且這些核心線程沒有超時機制,另外任務隊列也是沒有大小限制的
/* * @param nThreads the number of threads in the pool * @return the newly created thread pool * */ public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
CachedThreadPool
經過Executors的newCachedThreadPool方法來建立。它是一種線程數量不定的線程池,它只有非核心線程,而且最大線程數爲Integer.MAX_VALUE。因爲Integer.MAX_VALUE是一個很大的數,實際上就至關於最大線程數能夠任意大。當線程池中的線程都處於活動狀態時,線程池會建立新的線程來處理新任務,不然就會利用空閒的線程來處理新的任務。線程池中的空閒線程都有超時機制,這個超時時長爲60秒,超過60秒閒置線程就會被回收。和FixedThreadPool不一樣的是,CachedThreadPool的任務隊列其實至關於一個空集合,這將致使任何任務都會當即被執行,由於這種狀況下SynchronousQueue是沒法插入任務的。SynchronousQueue是一個很是特殊的隊列,不少狀況下能夠理解爲一個沒法存儲元素的隊列(實際中不多使用)。從CachedThreadPool的特性來看這類線程池比較適合執行大量的耗時較少的任務。當整個線程池都處於閒置狀態時,線程池中的線程都會超時而被中止,這個時候CachedThreadPool之中是沒有任何線程的,它幾乎不佔用任何系統資源的。
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
ScheduledThreadPoll
經過Executors的newScheduledThreadPool方法來建立。它的核心線程數量是固定的,而非核心線程數量是沒有限制的,而且當核心線程閒置時會被當即收回。ScheduledThreadPoll這類線程主要用於執行定時任務和具備固定週期的重複任務
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); } public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), threadFactory); }
SingleThreadExecutor
經過Executors的newSingleThreadExecutor方法來建立。這類線程池內部只有一個核心線程,它確保全部的任務都在同一個線程中順序執行。SingleThreadExecutor的意義在於統一全部的外界任務到一個線程中,這使得在這些任務之間不須要處理線程同步的問題。
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }