線程
在java中實現(xiàn)線程的方式:
- 繼承Thread類
- 實現(xiàn)Runable接口。
main方法其實也是一個線程。
在java中,每次程序運行至少啟動2個線程。一個是main線程,一個是垃圾收集線程。
對比
實現(xiàn)Runnable接口比繼承Thread類所具有的優(yōu)勢:
1):適合多個相同的程序代碼的線程去處理同一個資源
2):可以避免java中的單繼承的限制
3):增加程序的健壯性,代碼可以被多個線程共享,代碼和數(shù)據(jù)獨立-
yield()方法
Thread.yield()方法作用是:暫停當前正在執(zhí)行的線程對象,并執(zhí)行其他線程。
yield()應該做的是讓當前運行線程回到可運行狀態(tài),以允許具有相同優(yōu)先級的其他線程獲得運行機會。因此,使用yield()的目的是讓相同優(yōu)先級的線程之間能適當?shù)妮嗈D執(zhí)行。但是,實際中無法保證yield()達到讓步目的,因為讓步的線程還有可能被線程調度程序再次選中。
結論:yield()從未導致線程轉到等待/睡眠/阻塞狀態(tài)。在大多數(shù)情況下,yield()將導致線程從運行狀態(tài)轉到可運行狀態(tài),但有可能沒有效果。
-
join()方法
保證當前線程停止執(zhí)行,直到該線程所加入的線程完成為止,當前線程方可繼續(xù)執(zhí)行。然而,如果它加入的線程沒有存活,則當前線程不需要停止。
AsyncTask
- 內部由兩個線程池和一個Handler組成。
- SerialExecutor:用于任務的排隊,一次執(zhí)行一個。
- ThreadPoolExecutor:用于真正的執(zhí)行任務。
- InternalHandler:用于發(fā)送結果數(shù)據(jù)從子線程到主線程。
- 執(zhí)行流程:
構造方法中實例化WorkerRunnable和FutureTask對象。
WorkerRunnable將Params參數(shù)封裝,并將自己封裝在FutureTask中,一旦FutureTask執(zhí)行run方法時,會去調用WorkRunnable的call方法并返回Result值。call方法中就執(zhí)行了AsyncTask的doInBackground方法。并調用postResult方法將結果發(fā)送出去。
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是什么時候執(zhí)行的?
FutureTask充當了Runnable的作用,交給SerialExecutor的execute方法執(zhí)行。FutureTask是一個并發(fā)類,可以中途取消的用于異步計算的類。
SerialExecutor的execute方法首先把FutureTask插入到mTasks任務隊列中,如果沒有活動的任務,則執(zhí)行下一個。當一個任務執(zhí)行完成,會繼續(xù)調用scheduleNext方法執(zhí)行下一個,直到所有任務都被執(zhí)行。
THREAD_POOL_EXECUTOR.execute(mActive);才是真正執(zhí)行任務的方法。使用的是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 {
// 執(zhí)行FutureTask的run方法,進而執(zhí)行call方法
r.run();
} finally {
// 串行執(zhí)行下一個任務
scheduleNext();
}
}
});
//沒有正在活動的任務,執(zhí)行下一個AsyncTask。
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
- 注意:
- AsyncTask對象必須在主線程中創(chuàng)建
- execute必須在主線程中調用
- 一個AsyncTask只能調用一次execute方法,
HandlerThread
繼承了Thread類,本質還是線程。但是可以直接使用Handler的Thread。在run方法中通過Looper.prepare創(chuàng)建消息隊列,并開啟消息循環(huán)。使得可以再此線程中創(chuàng)建Handler。
由于loop開啟了無限循環(huán),因此可以通過quit或者quitSafely方法終止線程執(zhí)行。
同時,它還解決了一個Looper與Handler的同步問題??梢员WC根據(jù)當前線程的Looper創(chuàng)建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;
}
典型應用場景就是在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,任務執(zhí)行完畢后會自動關閉。
相對于線程而言,IntentService更適合執(zhí)行一些高優(yōu)先級的后臺任務。
@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);
}
線程池
- 優(yōu)點
- 重用線程池中的線程,避免因為線程的創(chuàng)建和銷毀帶來的性能開銷。
- 有效控制線程的最大并發(fā)數(shù),避免因大量的線程之間互相搶占系統(tǒng)資源而導致的阻塞 。
- 能夠對線程進行簡單的管理,并提供定時執(zhí)行和執(zhí)行循環(huán)間隔執(zhí)行等功能
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) { }
-
變量
- corePoolSize: 核心線程數(shù)
- maximumPoolSize: 最大線程數(shù)
- workQueue:任務隊列,提交的Runnable對象存儲在這里。
- keepAliveTime: 非核心線程存活時間
- unit:keepAliveTime的時間單位。
- threadFactory:為線程池提供新線程的工廠。
- handler:異常處理策略。
規(guī)則
- 如果此時線程池中的數(shù)量小于corePoolSize,即使線程池中的線程都處于空閑狀態(tài),也要創(chuàng)建新的線程來處理被添加的任務。
- 如果此時線程池中的數(shù)量等于 corePoolSize,但是緩沖隊列 workQueue未滿,那么任務被放入緩沖隊列。
- 如果此時線程池中的數(shù)量大于corePoolSize,緩沖隊列workQueue滿,并且線程池中的數(shù)量小于maximumPoolSize,建新的線程來處理被添加的任務。
- 如果此時線程池中的數(shù)量大于corePoolSize,緩沖隊列workQueue滿,并且線程池中的數(shù)量等于maximumPoolSize,那么通過 handler所指定的策略來處理此任務。
參閱:
Java多線程學習