執行緒
在java中實現執行緒的方式:
- 繼承Thread類
- 實現Runable介面。
main方法其實也是一個執行緒。
在java中,每次程式執行至少啟動2個執行緒。一個是main執行緒,一個是垃圾收集執行緒。
- 對比
實現Runnable介面比繼承Thread類所具有的優勢:
1):適合多個相同的程式程式碼的執行緒去處理同一個資源
2):可以避免java中的單繼承的限制
3):增加程式的健壯性,程式碼可以被多個執行緒共享,程式碼和資料獨立
-
yield()方法
Thread.yield()方法作用是:暫停當前正在執行的執行緒物件,並執行其他執行緒。
yield()應該做的是讓當前執行執行緒回到可執行狀態,以允許具有相同優先順序的其他執行緒獲得執行機會。因此,使用yield()的目的是讓相同優先順序的執行緒之間能適當的輪轉執行。但是,實際中無法保證yield()達到讓步目的,因為讓步的執行緒還有可能被執行緒排程程式再次選中。結論:yield()從未導致執行緒轉到等待/睡眠/阻塞狀態。在大多數情況下,yield()將導致執行緒從執行狀態轉到可執行狀態,但有可能沒有效果。
-
join()方法
保證當前執行緒停止執行,直到該執行緒所加入的執行緒完成為止,當前執行緒方可繼續執行。然而,如果它加入的執行緒沒有存活,則當前執行緒不需要停止。
AsyncTask
- 內部由兩個執行緒池和一個Handler組成。
- SerialExecutor:用於任務的排隊,一次執行一個。
- ThreadPoolExecutor:用於真正的執行任務。
- InternalHandler:用於傳送結果資料從子執行緒到主執行緒。
-
執行流程:
構造方法中例項化WorkerRunnable和FutureTask物件。
WorkerRunnable將Params引數封裝,並將自己封裝在FutureTask中,一旦FutureTask執行run方法時,會去呼叫WorkRunnable的call方法並返回Result值。call方法中就執行了AsyncTask的doInBackground方法。並呼叫postResult方法將結果傳送出去。mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked Result result = doInBackground(mParams); Binder.flushPendingCommands(); return postResult(result); } }; private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }複製程式碼
那麼FutureTask是什麼時候執行的?
FutureTask充當了Runnable的作用,交給SerialExecutor的execute方法執行。FutureTask是一個併發類,可以中途取消的用於非同步計算的類。SerialExecutor的execute方法首先把FutureTask插入到mTasks任務佇列中,如果沒有活動的任務,則執行下一個。當一個任務執行完成,會繼續呼叫scheduleNext方法執行下一個,直到所有任務都被執行。
THREAD_POOL_EXECUTOR.execute(mActive);才是真正執行任務的方法。使用的是ThreadPoolExecutor執行緒池。
private static class SerialExecutor implements Executor { final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); Runnable mActive; public synchronized void execute(final Runnable r) { //將FutureTask插入到mTasks任務佇列中 mTasks.offer(new Runnable() { public void run() { try { // 執行FutureTask的run方法,進而執行call方法 r.run(); } finally { // 序列執行下一個任務 scheduleNext(); } } }); //沒有正在活動的任務,執行下一個AsyncTask。 if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } } }複製程式碼
-
注意:
- AsyncTask物件必須在主執行緒中建立
- execute必須在主執行緒中呼叫
- 一個AsyncTask只能呼叫一次execute方法,
HandlerThread
繼承了Thread類,本質還是執行緒。但是可以直接使用Handler的Thread。在run方法中通過Looper.prepare建立訊息佇列,並開啟訊息迴圈。使得可以再次執行緒中建立Handler。
同時,它還解決了一個Looper與Handler的同步問題。可以保證根據當前執行緒的Looper建立Handler時,Looper物件的獲取不為空。
參考《深入理解Android 卷I》159頁
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason is isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
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 {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}複製程式碼
由於loop開啟了無限迴圈,因此可以通過quit或者quitSafely方法終止執行緒執行。
典型應用場景就是在IntentService中。
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}複製程式碼
IntentService
一個可以處理非同步請求的Service.服務開啟後,工作執行緒會依次處理每個Intent,任務執行完畢後會自動關閉。
相對於執行緒而言,IntentService更適合執行一些高優先順序的後臺任務。
@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);
}複製程式碼
執行緒池
- 優點
- 重用執行緒池中的執行緒,避免因為執行緒的建立和銷燬帶來的效能開銷。
- 有效控制執行緒的最大併發數,避免因大量的執行緒之間互相搶佔系統資源而導致的阻塞 。
- 能夠對執行緒進行簡單的管理,並提供定時執行和執行迴圈間隔執行等功能
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) { }複製程式碼
-
變數
- corePoolSize: 核心執行緒數
- maximumPoolSize: 最大執行緒數
- workQueue:任務佇列,提交的Runnable物件儲存在這裡。
- keepAliveTime: 非核心執行緒存活時間
- unit:keepAliveTime的時間單位。
- threadFactory:為執行緒池提供新執行緒的工廠。
- handler:異常處理策略。
-
規則
- 如果此時執行緒池中的數量小於corePoolSize,即使執行緒池中的執行緒都處於空閒狀態,也要建立新的執行緒來處理被新增的任務。
- 如果此時執行緒池中的數量等於 corePoolSize,但是緩衝佇列 workQueue未滿,那麼任務被放入緩衝佇列。
- 如果此時執行緒池中的數量大於corePoolSize,緩衝佇列workQueue滿,並且執行緒池中的數量小於maximumPoolSize,建新的執行緒來處理被新增的任務。
- 如果此時執行緒池中的數量大於corePoolSize,緩衝佇列workQueue滿,並且執行緒池中的數量等於maximumPoolSize,那麼通過 handler所指定的策略來處理此任務。