除了Thread,Android中扮演線程的角色還有:AsyncTask、HandlerThread、IntentService。
- AsyncTask:內(nèi)部封裝線程池、handler,便于在子線程中更新UI。
- HandlerThread:可以使用消息循環(huán)的線程,在它內(nèi)部可以使用Handler。
- IntentService:內(nèi)部使用HandlerThread執(zhí)行任務(wù),完畢后會(huì)自動(dòng)退出。(相比后臺(tái)線程)因是組件,優(yōu)先級(jí)高,不易被殺死。
線程是操作系統(tǒng)調(diào)度的最小單元,是一種受限的資源,不可能無(wú)限制的產(chǎn)生。且線程的創(chuàng)建和銷毀需要相應(yīng)的開(kāi)銷。且存在大量線程時(shí),系統(tǒng)會(huì)通過(guò)時(shí)間片輪轉(zhuǎn)的方式調(diào)度線程,因此線程不可能做到并行,除非線程數(shù)小于等于cpu數(shù)。所以需要 線程池,它可以緩存一定數(shù)量的線程,避免頻繁地線程創(chuàng)建和銷毀帶來(lái)的系統(tǒng)開(kāi)銷。
一、Android中的線程形態(tài)
1.1 AsyncTask
AsyncTask是用來(lái)在線程池中處理異步任務(wù),并可以把處理進(jìn)度和結(jié)果發(fā)送到UI線程。
1.1.1 使用方法
AsyncTask的基本使用方法,示例如下:
private void testAsyncTask() {
//一般要在主線程實(shí)例化。(實(shí)際在9.0上 子線程創(chuàng)建實(shí)例然后主線程execute沒(méi)問(wèn)題)
//三個(gè)泛型參數(shù)依次表示參數(shù)類型、進(jìn)度類型、結(jié)果類型。
//覆寫的這幾個(gè)方法不可以直接調(diào)用
AsyncTask<Integer, Integer, String> task = new AsyncTask<Integer, Integer, String>() {
@Override
protected void onPreExecute() {
super.onPreExecute();
//主線程執(zhí)行,在異步任務(wù)之前
Log.i(TAG, "testAsyncTask onPreExecute: ");
}
@Override
protected String doInBackground(Integer... integers) {
Log.i(TAG, "testAsyncTask doInBackground: ");
//任務(wù)在 線程池中執(zhí)行 耗時(shí)操作
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//發(fā)出進(jìn)度
publishProgress(50);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//再發(fā)出進(jìn)度
publishProgress(100);
return "我是結(jié)果。參數(shù)是" + integers[0];
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
//在主線程執(zhí)行,在異步任務(wù)執(zhí)行完之后
Log.i(TAG, "testAsyncTask onPostExecute: "+s);
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
//執(zhí)行在主線程,調(diào)用publishProgress()后就會(huì)執(zhí)行
Log.i(TAG, "testAsyncTask onProgressUpdate: 進(jìn)度:"+values[0]+"%");
}
@Override
protected void onCancelled() {
super.onCancelled();
//取消任務(wù)
}
};
//必須要在主線程執(zhí)行execute,且只能執(zhí)行一次
task.execute(100);
}
執(zhí)行結(jié)果日志如下:
2020-01-14 11:29:03.510 13209-13209/com.hfy.demo01 I/hfy: testAsyncTask onPreExecute:
2020-01-14 11:29:03.511 13209-13282/com.hfy.demo01 I/hfy: testAsyncTask doInBackground:
2020-01-14 11:29:04.558 13209-13209/com.hfy.demo01 I/hfy: testAsyncTask onProgressUpdate: 進(jìn)度:50%
2020-01-14 11:29:05.589 13209-13209/com.hfy.demo01 I/hfy: testAsyncTask onProgressUpdate: 進(jìn)度:100%
2020-01-14 11:29:05.590 13209-13209/com.hfy.demo01 I/hfy: testAsyncTask onPostExecute: 我是結(jié)果。參數(shù)是100
1.1.2 原理分析:
先看構(gòu)造方法
public AsyncTask() {
this((Looper) null);
}
public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
//執(zhí)行完,發(fā)出結(jié)果
postResult(result);
}
return result;
}
};
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 occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
//這里傳入的是主線程的looper,所以用來(lái)把消息切到主線程
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
看到,首先使用主線程的Looper創(chuàng)建了InternalHandler實(shí)例。然后創(chuàng)建了WorkerRunnable的實(shí)例mWorker,call方法中看到調(diào)用了 doInBackground(mParams),可以猜想call方法是執(zhí)行在線程池的。然后創(chuàng)建了FutureTask的實(shí)例mFuture并傳入了mWorker,mFuture怎么使用的呢?后面會(huì)分析道。我們可以先看下Handler的實(shí)現(xiàn)InternalHandler:
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@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;
}
}
}
看到有處理發(fā)送結(jié)果、處理發(fā)送進(jìn)度的消息。消息從哪發(fā)來(lái)的呢?先留個(gè)疑問(wèn)。繼續(xù)看AsyncTask的execute方法:
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
/**
* 串行 執(zhí)行器
*/
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@MainThread
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方法走到了executeOnExecutor方法,先進(jìn)行當(dāng)前任務(wù)狀態(tài)的判斷,默認(rèn)是準(zhǔn)備執(zhí)行任務(wù)的PENDING狀態(tài),然后變?yōu)镽UNNING。但如果正在執(zhí)行的RUNNING、執(zhí)行完的FINISHED都會(huì)拋出異常。這也是一個(gè)任務(wù)實(shí)例只能執(zhí)行一次的原因。然后又走到了onPreExecute(),因?yàn)閑xecute執(zhí)行在UI線程 所以也解釋了其是執(zhí)行在UI線程的原因。接著把參數(shù)賦值給mWorker,mFuture作為參數(shù)執(zhí)行 靜態(tài)的sDefaultExecutor的execute()方法。注意到sDefaultExecutor是SerialExecutor實(shí)例,去瞅瞅:
//線程池
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
//execute方法加了鎖
public synchronized void execute(final Runnable r) {
//把r存入到任務(wù)隊(duì)列的隊(duì)尾
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
//任務(wù)執(zhí)行完,就執(zhí)行下一個(gè)
scheduleNext();
}
}
});
//把r存入任務(wù)隊(duì)列后,然后當(dāng)前沒(méi)有取出的任務(wù),就 取 隊(duì)列頭部 的任務(wù)執(zhí)行
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
//取 隊(duì)列頭部 的任務(wù)執(zhí)行
if ((mActive = mTasks.poll()) != null) {
//THREAD_POOL_EXECUTOR是線程池
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
上面都有注釋,可見(jiàn)SerialExecutor就是串行執(zhí)行器,最終執(zhí)行在THREAD_POOL_EXECUTOR的線程池中。r.run()實(shí)際走的是FutureTask的run方法:
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
//callable的call方法
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
FutureTask的run方法中調(diào)用的傳入的callable的call()方法,再結(jié)合上面AsyncTask的構(gòu)造方法,mWorker就是實(shí)現(xiàn)callable的call()方法。所以里面的doInBackground方法就會(huì)串行的執(zhí)行在線程池中。因?yàn)榇?,那使用execute方法不能執(zhí)行特別耗時(shí)的任務(wù),否則會(huì)阻塞后面等待的任務(wù)。若想要并行,可采用AsyncTask的executeOnExecutor方法,傳入線程池THREAD_POOL_EXECUTOR即可。
還注意到,doInBackground執(zhí)行完后調(diào)用了postResult(result),result就是doInBackground返回值:
private Handler getHandler() {
return mHandler;
}
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
看到,使用handler發(fā)送消息,消息類型就是MESSAGE_POST_RESULT,前面看到InternalHandler內(nèi)部handleMessage是有處理的,就是調(diào)用task的finish方法:
private void finish(Result result) {
if (isCancelled()) {
//如果任務(wù)取消了,回調(diào)onCancelled
onCancelled(result);
} else {
//沒(méi)有取消
onPostExecute(result);
}
//修改任務(wù)狀態(tài)為完成
mStatus = Status.FINISHED;
}
可見(jiàn)如果沒(méi)有調(diào)用cancel(),就會(huì)走onPostExecute,所以onPostExecute也是執(zhí)行在UI線程的。
最后看下publishProgress方法:
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
如果沒(méi)有取消任務(wù),也是用handler,消息類型就是MESSAGE_POST_PROGRESS,前面看到InternalHandler內(nèi)部handleMessage是有處理的,最后在UI線程執(zhí)行onProgressUpdate方法。
舉兩個(gè)例子??
例子1,默認(rèn)的串行執(zhí)行:
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
Log.i(TAG, "task1 SERIAL_EXECUTOR doInBackground: ");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}.execute();
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
Log.i(TAG, "task2 SERIAL_EXECUTOR doInBackground: ");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}.execute();
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
Log.i(TAG, "task3 SERIAL_EXECUTOR doInBackground: ");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}.execute();
執(zhí)行結(jié)果如下,每隔兩秒打印一次,可見(jiàn)是串行執(zhí)行。
2020-01-16 14:51:40.836 13346-13599/com.hfy.demo01 I/hfy: task1 SERIAL_EXECUTOR doInBackground:
2020-01-16 14:51:42.876 13346-13598/com.hfy.demo01 I/hfy: task2 SERIAL_EXECUTOR doInBackground:
2020-01-16 14:51:44.915 13346-13599/com.hfy.demo01 I/hfy: task3 SERIAL_EXECUTOR doInBackground:
例子2,并行執(zhí)行-直接使用線程池:
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
Log.i(TAG, "task1 THREAD_POOL_EXECUTOR doInBackground: ");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
Log.i(TAG, "task2 THREAD_POOL_EXECUTOR doInBackground: ");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
Log.i(TAG, "task3 THREAD_POOL_EXECUTOR doInBackground: ");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
執(zhí)行結(jié)果如下,同時(shí)打印出來(lái),可見(jiàn)是并行執(zhí)行。
2020-01-16 14:51:38.772 13346-13599/com.hfy.demo01 I/hfy: task1 THREAD_POOL_EXECUTOR doInBackground:
2020-01-16 14:51:38.773 13346-13600/com.hfy.demo01 I/hfy: task2 THREAD_POOL_EXECUTOR doInBackground:
2020-01-16 14:51:38.774 13346-13601/com.hfy.demo01 I/hfy: task3 THREAD_POOL_EXECUTOR doInBackground:
總結(jié)一下,AsyncTask內(nèi)部默認(rèn) 使用串行執(zhí)行器 串行地 在線程池 執(zhí)行任務(wù),我們也可以使用executeOnExecutor直接使用線程池并行執(zhí)行。內(nèi)部使用handler把進(jìn)度和結(jié)果從線程池切換到UI線程。
1.2 HandlerThread
HandlerThread繼承自Thread,內(nèi)部已準(zhǔn)備了Looper并已開(kāi)啟循環(huán)。所以可以在UI線程使用handler發(fā)送任務(wù)到HandlerThread中執(zhí)行,且可以隨意多次發(fā)送任務(wù)。(而普通thread執(zhí)行完run方法中的耗時(shí)操作就結(jié)束了。)當(dāng)不使用時(shí) 如onDestroy中,使用quit()或quitSafely()退出即可。
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
//looper開(kāi)啟之前可以做一些事情
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
//給當(dāng)前線程準(zhǔn)備Looper實(shí)例
Looper.prepare();
//加鎖,保證能獲取到looer實(shí)例
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
//開(kāi)啟循環(huán)
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
//獲取不到就等 run中的notifyAll()被調(diào)用
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
//直接退出
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
//安全退出(執(zhí)行完正在正在執(zhí)行的任務(wù)再退出)
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
public int getThreadId() {
return mTid;
}
}
舉個(gè)例子??
private void testHandlerThread() {
HandlerThread handlerThread = new HandlerThread("HandlerThreadName");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1000:
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG, "handleMessage: thread name="+Thread.currentThread().getName()+",what="+msg.what);
break;
case 1001:
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG, "handleMessage: thread name="+Thread.currentThread().getName()+",what="+msg.what);
break;
default:
break;
}
}
};
Log.i(TAG, "sendMessage thread name="+Thread.currentThread().getName());
handler.sendMessage(Message.obtain(handler, 1000));
handler.sendMessage(Message.obtain(handler, 1001));
}
可見(jiàn)在主線程發(fā)送了兩個(gè)任務(wù),順序執(zhí)行在HandlerThread了。
2020-01-16 17:12:46.832 16293-16293/com.hfy.demo01 I/hfy: sendMessage thread name=main
2020-01-16 17:12:48.833 16293-17187/com.hfy.demo01 I/hfy: handleMessage: thread name=HandlerThreadName,what=1000
2020-01-16 17:12:49.834 16293-17187/com.hfy.demo01 I/hfy: handleMessage: thread name=HandlerThreadName,what=1001
1.3 IntentService
IntentService是繼承自Service的抽象類,可執(zhí)行后臺(tái)耗時(shí)任務(wù),執(zhí)行完后會(huì)自動(dòng)停止。
因?yàn)槭荢ervice,即是Android的組件,優(yōu)先級(jí)比單純的線程高,不容易被系統(tǒng)殺死,所以可用來(lái)執(zhí)行優(yōu)先級(jí)高的后臺(tái)任務(wù),
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
//內(nèi)部類handler
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
//先回調(diào)出去,待IntentService子類覆寫自己的邏輯
onHandleIntent((Intent)msg.obj);
//結(jié)束service自己,msg.arg1是標(biāo)記某次startService的Id。
//但如果此時(shí)外部又調(diào)用了startService,那么最新的請(qǐng)求id就不是msg.arg1了,所以下面這句就不會(huì)結(jié)束service。
stopSelf(msg.arg1);
}
}
//name是線程名
public IntentService(String name) {
super();
mName = name;
}
...
@Override
public void onCreate() {
super.onCreate();
//創(chuàng)建HandlerThread實(shí)例 并啟動(dòng)
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//創(chuàng)建對(duì)應(yīng)looper的handler,所以mServiceHandler的handleMessage執(zhí)行在 線程中
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
//發(fā)送消息,參數(shù)是startId、intent
//每次startService() 都會(huì)走這里
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
//退出looper循環(huán)
mServiceLooper.quit();
}
...
//執(zhí)行子在線程,同時(shí)只存在一個(gè)intent(因?yàn)閘ooper的隊(duì)列),所以如果此方法執(zhí)行時(shí)間過(guò)長(zhǎng),會(huì)阻塞其他請(qǐng)求,所有請(qǐng)求執(zhí)行完,service會(huì)自動(dòng)停止,所以不能手動(dòng)調(diào)用stopSelf。
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
onCreate中創(chuàng)建了HandlerThread實(shí)例,對(duì)應(yīng)的Handler實(shí)例mServiceHandler,所以mServiceHandler發(fā)送的任務(wù)都會(huì)在線程中執(zhí)行。
onStartCommand中調(diào)用的是onStart,onStart中確實(shí)使用mServiceHandler發(fā)送消息,攜帶的參數(shù)是startId、intent,startId是每次啟動(dòng)service的標(biāo)記,intent就是啟動(dòng)service的intent。
onDestroy中退出looper循環(huán)。
發(fā)送的消息在哪處理的呢?
那就看ServiceHandler,其繼承自Handler,handleMessage方法中先調(diào)用了抽象方法onHandleIntent((Intent)msg.obj),參數(shù)就是啟動(dòng)service的intent。所以IntentService 的子類必須要重寫onHandleIntent,并處理這個(gè)intent。因?yàn)閙ServiceHandler拿到的HandlerThread的looper,所以這個(gè)onHandleIntent()就是執(zhí)行在子線程中的。
接著調(diào)用了stopSelf(msg.arg1),msg.arg1)就是前面說(shuō)的啟動(dòng)service的標(biāo)記。對(duì)stopSelf(int startId)說(shuō)明如下:
startId:代表啟動(dòng)服務(wù)的次數(shù),由系統(tǒng)生成。
stopSelf(int startId):在其參數(shù)startId跟 最后啟動(dòng)該service時(shí)生成的ID相等時(shí)才會(huì)執(zhí)行停止服務(wù)。stopSelf():直接停止服務(wù)。
使用場(chǎng)景: 如果同時(shí)有多個(gè)服務(wù)啟動(dòng)請(qǐng)求發(fā)送到onStartCommand(),不應(yīng)該在處理完一個(gè)請(qǐng)求后調(diào)用stopSelf();因?yàn)樵谡{(diào)用此函數(shù)銷毀service之前,可能service又接收到新的啟動(dòng)請(qǐng)求,如果此時(shí)service被銷毀,新的請(qǐng)求將得不到處理。此情況應(yīng)該調(diào)用stopSelf(int startId)。
所以,當(dāng)多次啟動(dòng)service,就會(huì)多次調(diào)用 onStart,那么會(huì)有多個(gè)任務(wù)發(fā)出,當(dāng)每次任務(wù)執(zhí)行完onHandleIntent時(shí),stopSelf(int startId)中會(huì)判斷,若又啟動(dòng)service那么就不會(huì)停止。那么looper繼續(xù)取下個(gè)消息繼續(xù)處理。直到stopSelf中的startId和最新啟動(dòng)的startId相同,就會(huì)停止。因?yàn)槭莑ooper,所以這些任務(wù)都是按啟動(dòng)service的順序執(zhí)行的。
舉個(gè)例子??
private void testIntentService() {
Intent intent= new Intent(this, MyIntentService.class);
intent.putExtra("task_name","task1");
startService(intent);
intent.putExtra("task_name","task2");
startService(intent);
intent.putExtra("task_name","task3");
startService(intent);
}
public static class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentServiceThread");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.i(TAG, "MyIntentService onHandleIntent: begin."+intent.getStringExtra("task_name"));
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG, "MyIntentService onHandleIntent: done."+intent.getStringExtra("task_name"));
}
@Override
public void onDestroy() {
Log.i(TAG, "MyIntentService onDestroy: ");
super.onDestroy();
}
}
2020-01-17 09:58:44.639 11117-11236/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: begin.task1
2020-01-17 09:58:46.640 11117-11236/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: done.task1
2020-01-17 09:58:46.641 11117-11236/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: begin.task2
2020-01-17 09:58:48.642 11117-11236/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: done.task2
2020-01-17 09:58:48.644 11117-11236/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: begin.task3
2020-01-17 09:58:50.645 11117-11236/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: done.task3
2020-01-17 09:58:50.650 11117-11117/com.hfy.demo01 I/hfy: MyIntentService onDestroy:
靜態(tài)內(nèi)部類MyIntentService繼承IntentService并重寫了onHandleIntent,就是睡兩秒。然后不間斷連續(xù)啟動(dòng)3次,由日志可見(jiàn)是順序執(zhí)行的,最后都執(zhí)行完才走到onDestroy。
再看,如果是間隔三秒發(fā)送呢:
private void testIntentService() {
Log.i(TAG, "testIntentService: task1");
Intent intent= new Intent(this, MyIntentService.class);
intent.putExtra("task_name","task1");
startService(intent);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Log.i(TAG, "testIntentService: task2");
intent.putExtra("task_name","task2");
startService(intent);
}
}, 3000);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Log.i(TAG, "testIntentService: task3");
intent.putExtra("task_name","task3");
startService(intent);
}
}, 3000);
}
2020-01-17 10:16:29.335 14739-14739/com.hfy.demo01 I/hfy: testIntentService: task1
2020-01-17 10:16:29.698 14739-14843/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: begin.task1
2020-01-17 10:16:31.698 14739-14843/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: done.task1
2020-01-17 10:16:31.701 14739-14739/com.hfy.demo01 I/hfy: MyIntentService onDestroy:
2020-01-17 10:16:32.371 14739-14739/com.hfy.demo01 I/hfy: testIntentService: task2
2020-01-17 10:16:32.390 14739-14862/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: begin.task2
2020-01-17 10:16:34.391 14739-14862/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: done.task2
2020-01-17 10:16:34.451 14739-14739/com.hfy.demo01 I/hfy: MyIntentService onDestroy:
2020-01-17 10:16:35.339 14739-14739/com.hfy.demo01 I/hfy: testIntentService: task3
2020-01-17 10:16:35.364 14739-14873/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: begin.task3
2020-01-17 10:16:37.364 14739-14873/com.hfy.demo01 I/hfy: MyIntentService onHandleIntent: done.task3
2020-01-17 10:16:37.367 14739-14739/com.hfy.demo01 I/hfy: MyIntentService onDestroy:
可見(jiàn)每個(gè)任務(wù)執(zhí)行完 就走onDestroy了。這是因?yàn)楫?dāng)一個(gè)任務(wù)執(zhí)行完,走到stopSelf(int startId)時(shí),后面還沒(méi)有再次開(kāi)啟service,所以此時(shí)的stopSelf中的startId就是最新的,所以就會(huì)停止服務(wù)了。
二、Android中的線程池
線程池優(yōu)點(diǎn)如下:
- 能夠重用線程池中的線程,避免線程的創(chuàng)建、銷毀帶來(lái)的性能開(kāi)銷。
- 能有效控制線程池中的最大并發(fā)數(shù),避免大量的線程之間因互相搶占系統(tǒng)資源而導(dǎo)致的阻塞現(xiàn)象。
- 能對(duì)線程進(jìn)行簡(jiǎn)單管理,并提供定時(shí)執(zhí)行、指定間隔循環(huán)執(zhí)行的功能。
Android中的線程池來(lái)源于Java的Executor,正在的實(shí)現(xiàn)是ThreadPoolExecutor。
2.1 ThreadPoolExecutor
ThreadPoolExecutor是線程池的真正實(shí)現(xiàn),看下其構(gòu)造方法里的參數(shù),參數(shù)會(huì)影響線程池的功能特性。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
- corePoolSize,核心線程數(shù),默認(rèn)一般核心線程會(huì)在線程池中一直存活,即使處理空閑狀態(tài)。但當(dāng)allowCoreThreadTimeOut設(shè)置為true,那么核心線程就會(huì)有閑置超時(shí)時(shí)間,閑置超過(guò)超時(shí)時(shí)間就會(huì)終止。超時(shí)時(shí)間由keepAliveTime和unit指定。
- maximumPoolSize,最大線程數(shù),當(dāng)活動(dòng)線程到達(dá)這個(gè)數(shù),后續(xù)的新任務(wù)會(huì)被阻塞。
- keepAliveTime,非核心線程閑置時(shí) 的超時(shí)時(shí)長(zhǎng)。非核心線程閑置時(shí)間超過(guò)此時(shí)間就會(huì)被回收。當(dāng)allowCoreThreadTimeOut設(shè)置為true,keepAliveTime也會(huì)作用于核心線程。
- unit,是keepAliveTime的時(shí)間單位,取值是枚舉,有TimeUnit.MINUTES、TimeUnit.SECONDS、TimeUnit.MILLISECONDS等。
- workQueue,線程池中的任務(wù)隊(duì)列,通過(guò)線程池的execute方法提交的Runnable會(huì)存在這個(gè)隊(duì)列中。
- threadFactory,線程工廠,為線程池提供創(chuàng)建新線程的能力。
還有個(gè)不常用參數(shù)RejectedExecutionHandler handler,調(diào)用其rejectedExecution()方法來(lái)處理 當(dāng)任務(wù)隊(duì)列已滿 時(shí) 不能執(zhí)行新任務(wù)的情況。handler的默認(rèn)實(shí)現(xiàn)是AbortPolicy,rejectedExecution()中會(huì)直接拋出異常RejectedExecutionException。其他實(shí)現(xiàn)如DiscardPolicy的rejectedExecution()中是不做任何事。還有CallerRunsPolicy、DiscardOldestPolicy。
==ThreadPoolExecutor執(zhí)行任務(wù)的執(zhí)行規(guī)則== 如下:
- 如果線程池中的線程數(shù)未到達(dá)核心線程數(shù),那么會(huì)直接啟動(dòng)一個(gè)核心線程來(lái)執(zhí)行這個(gè)任務(wù)。(不管已啟動(dòng)的核心線程是否空閑)
- 如果線程池中的線程數(shù)已到達(dá)或超過(guò)核心線程數(shù),那么任務(wù)會(huì)插入到任務(wù)隊(duì)列中排隊(duì)等待執(zhí)行。
- 如果2中 任務(wù)無(wú)法插入到隊(duì)列中,一般是對(duì)隊(duì)列已滿,若此時(shí)未達(dá)到最大線程數(shù),就會(huì)啟動(dòng)非核心線程執(zhí)行這個(gè)任務(wù)。
- 如果3中線程數(shù)達(dá)到最大線程數(shù),那么會(huì)拒絕執(zhí)行任務(wù),即會(huì)調(diào)用RejectedExecutionHandler的rejectedExecution()通知調(diào)用者。
我們看下AsyncTask中線程池的配置:
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;
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;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
可見(jiàn)THREAD_POOL_EXECUTOR這個(gè)線程池的配置如下:
- 核心線程數(shù),2-4個(gè)
- 最大線程數(shù),CPU核心數(shù)量 * 2 + 1
- 超時(shí)時(shí)間30s,允許核心線程超時(shí)
- 隊(duì)列容量128
2.2 線程池的分類
Android中常見(jiàn)的4類線程池,都是直接或間接配置ThreadPoolExecutor實(shí)現(xiàn)自己特性的,它們是FixedThreadPool、CachedThreadPool、ScheduledThreadPool、SingleThreadExecutor。它們都可以通過(guò)工具類Executors獲取。
2.2.1 FixedThreadPool
通過(guò)Executors的newFixedThreadPool方法獲得。固定的核心線程數(shù)量,沒(méi)有非核心線程,空閑時(shí)不會(huì)被回收,隊(duì)列長(zhǎng)度無(wú)限制。因?yàn)椴粫?huì)被回收,所以能快速執(zhí)行外界請(qǐng)求。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
2.2.2 CachedThreadPool
通過(guò)Executors的newCachedThreadPool方法獲得。核心線程數(shù)0,非核心線程數(shù)無(wú)限制,空閑回收超時(shí)時(shí)間60s,隊(duì)列不能插入任務(wù)。當(dāng)所有線程都處于活動(dòng)狀態(tài),就會(huì)創(chuàng)建新線程處理任務(wù),否則利用空閑線程處理任務(wù)。當(dāng)整個(gè)線程池空閑時(shí) 所有線程都會(huì)被回收,不占用系統(tǒng)資源。因此,適合執(zhí)行大量耗時(shí)較少的任務(wù)
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
2.2.3 ScheduledThreadPool
通過(guò)Executors的newScheduledThreadPool方法獲得。固定核心線程數(shù),不限制非核心線程數(shù),非核心線程閑置回收超時(shí)時(shí)間是10ms。一般用于執(zhí)行定時(shí)任務(wù)、固定周期的重復(fù)任務(wù)。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
2.2.4 SingleThreadExecutor
通過(guò)Executors的newSingleThreadExecutor方法獲得。僅有1個(gè)核心線程,不會(huì)回收??纱_保所有任務(wù)按順序執(zhí)行,不用處理線程同步的問(wèn)題 。
private void testThreadPoolExecutor() {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Log.i(TAG, "testThreadPoolExecutor: run begin");
Thread.sleep(4000);
Log.i(TAG, "testThreadPoolExecutor: run end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
fixedThreadPool.execute(runnable);
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
cachedThreadPool.execute(runnable);
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4);
scheduledThreadPool.execute(runnable);
//延遲2秒執(zhí)行
scheduledThreadPool.schedule(runnable, 2, TimeUnit.SECONDS);
//延遲2秒執(zhí)行,然后以每次 任務(wù)開(kāi)始的時(shí)間計(jì)時(shí), 1秒后,如果任務(wù)是結(jié)束的 就立刻執(zhí)行下一次;如果沒(méi)有結(jié)束,就等它結(jié)束后立即執(zhí)行下一次。
scheduledThreadPool.scheduleAtFixedRate(runnable, 0, 1, TimeUnit.SECONDS);
//延遲3秒執(zhí)行,然后以每次任務(wù)執(zhí)行完后的時(shí)間計(jì)時(shí), 2秒后,執(zhí)行下一次~
scheduledThreadPool.scheduleWithFixedDelay(runnable,1,2,TimeUnit.SECONDS);
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
singleThreadExecutor.execute(runnable);
}
注意點(diǎn):scheduledThreadPool使用時(shí)注意區(qū)分scheduleAtFixedRate、scheduleWithFixedDelay的循環(huán)任務(wù)的邏輯區(qū)別:
- scheduleAtFixedRate,以每次 任務(wù)開(kāi)始的時(shí)間計(jì)時(shí), period時(shí)間后,如果任務(wù)是結(jié)束的就立刻執(zhí)行下一次;如果沒(méi)有結(jié)束,就等它結(jié)束后立即執(zhí)行下一次。
- scheduleWithFixedDelay,以每次任務(wù)執(zhí)行完后的時(shí)間計(jì)時(shí),period時(shí)間后,執(zhí)行下一次。
并且,這兩個(gè)方法都是在任務(wù)結(jié)束后才執(zhí)行下一次,那么如果某個(gè)任務(wù)發(fā)生異無(wú)法執(zhí)行完,那么整個(gè)循環(huán)任務(wù)就會(huì)失效。所以需要給任務(wù)添加超時(shí)機(jī)制(比如給任務(wù)加上try-catch-finally,catch住超時(shí)異常) 保證任務(wù)即使發(fā)生異常也可以結(jié)束,就可保證循環(huán)正常執(zhí)行了。