線程
在java中實(shí)現(xiàn)線程的方式:
- 繼承Thread類
- 實(shí)現(xiàn)Runable接口点楼。
main方法其實(shí)也是一個(gè)線程糖儡。
在java中,每次程序運(yùn)行至少啟動(dòng)2個(gè)線程贷币。一個(gè)是main線程击胜,一個(gè)是垃圾收集線程。
對(duì)比
實(shí)現(xiàn)Runnable接口比繼承Thread類所具有的優(yōu)勢(shì):
1):適合多個(gè)相同的程序代碼的線程去處理同一個(gè)資源
2):可以避免java中的單繼承的限制
3):增加程序的健壯性役纹,代碼可以被多個(gè)線程共享潜的,代碼和數(shù)據(jù)獨(dú)立-
yield()方法
Thread.yield()方法作用是:暫停當(dāng)前正在執(zhí)行的線程對(duì)象,并執(zhí)行其他線程字管。
yield()應(yīng)該做的是讓當(dāng)前運(yùn)行線程回到可運(yùn)行狀態(tài),以允許具有相同優(yōu)先級(jí)的其他線程獲得運(yùn)行機(jī)會(huì)信不。因此嘲叔,使用yield()的目的是讓相同優(yōu)先級(jí)的線程之間能適當(dāng)?shù)妮嗈D(zhuǎn)執(zhí)行。但是抽活,實(shí)際中無(wú)法保證yield()達(dá)到讓步目的硫戈,因?yàn)樽尣降木€程還有可能被線程調(diào)度程序再次選中。
結(jié)論:yield()從未導(dǎo)致線程轉(zhuǎn)到等待/睡眠/阻塞狀態(tài)下硕。在大多數(shù)情況下丁逝,yield()將導(dǎo)致線程從運(yùn)行狀態(tài)轉(zhuǎn)到可運(yùn)行狀態(tài),但有可能沒有效果梭姓。
-
join()方法
保證當(dāng)前線程停止執(zhí)行霜幼,直到該線程所加入的線程完成為止,當(dāng)前線程方可繼續(xù)執(zhí)行誉尖。然而罪既,如果它加入的線程沒有存活,則當(dāng)前線程不需要停止铡恕。
AsyncTask
- 內(nèi)部由兩個(gè)線程池和一個(gè)Handler組成琢感。
- SerialExecutor:用于任務(wù)的排隊(duì),一次執(zhí)行一個(gè)探熔。
- ThreadPoolExecutor:用于真正的執(zhí)行任務(wù)驹针。
- InternalHandler:用于發(fā)送結(jié)果數(shù)據(jù)從子線程到主線程。
- 執(zhí)行流程:
構(gòu)造方法中實(shí)例化WorkerRunnable和FutureTask對(duì)象诀艰。
WorkerRunnable將Params參數(shù)封裝柬甥,并將自己封裝在FutureTask中饮六,一旦FutureTask執(zhí)行run方法時(shí),會(huì)去調(diào)用WorkRunnable的call方法并返回Result值暗甥。call方法中就執(zhí)行了AsyncTask的doInBackground方法喜滨。并調(diào)用postResult方法將結(jié)果發(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是什么時(shí)候執(zhí)行的撤防?
FutureTask充當(dāng)了Runnable的作用虽风,交給SerialExecutor的execute方法執(zhí)行。FutureTask是一個(gè)并發(fā)類寄月,可以中途取消的用于異步計(jì)算的類辜膝。
SerialExecutor的execute方法首先把FutureTask插入到mTasks任務(wù)隊(duì)列中,如果沒有活動(dòng)的任務(wù)漾肮,則執(zhí)行下一個(gè)厂抖。當(dāng)一個(gè)任務(wù)執(zhí)行完成,會(huì)繼續(xù)調(diào)用scheduleNext方法執(zhí)行下一個(gè)克懊,直到所有任務(wù)都被執(zhí)行忱辅。
THREAD_POOL_EXECUTOR.execute(mActive);才是真正執(zhí)行任務(wù)的方法。使用的是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任務(wù)隊(duì)列中
mTasks.offer(new Runnable() {
public void run() {
try {
// 執(zhí)行FutureTask的run方法墙懂,進(jìn)而執(zhí)行call方法
r.run();
} finally {
// 串行執(zhí)行下一個(gè)任務(wù)
scheduleNext();
}
}
});
//沒有正在活動(dòng)的任務(wù),執(zhí)行下一個(gè)AsyncTask扮念。
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
- 注意:
- AsyncTask對(duì)象必須在主線程中創(chuàng)建
- execute必須在主線程中調(diào)用
- 一個(gè)AsyncTask只能調(diào)用一次execute方法损搬,
HandlerThread
繼承了Thread類,本質(zhì)還是線程柜与。但是可以直接使用Handler的Thread巧勤。在run方法中通過(guò)Looper.prepare創(chuàng)建消息隊(duì)列,并開啟消息循環(huán)弄匕。使得可以再此線程中創(chuàng)建Handler颅悉。
由于loop開啟了無(wú)限循環(huán),因此可以通過(guò)quit或者quitSafely方法終止線程執(zhí)行粘茄。
同時(shí)签舞,它還解決了一個(gè)Looper與Handler的同步問(wèn)題∑獍辏可以保證根據(jù)當(dāng)前線程的Looper創(chuàng)建Handler時(shí)儒搭,Looper對(duì)象的獲取不為空。
參考《深入理解Android 卷I》159頁(yè)
/**
* 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;
}
典型應(yīng)用場(chǎng)景就是在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
一個(gè)可以處理異步請(qǐng)求的Service.服務(wù)開啟后搂鲫,工作線程會(huì)依次處理每個(gè)Intent,任務(wù)執(zhí)行完畢后會(huì)自動(dòng)關(guān)閉磺平。
相對(duì)于線程而言魂仍,IntentService更適合執(zhí)行一些高優(yōu)先級(jí)的后臺(tái)任務(wù)拐辽。
@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)點(diǎn)
- 重用線程池中的線程,避免因?yàn)榫€程的創(chuàng)建和銷毀帶來(lái)的性能開銷擦酌。
- 有效控制線程的最大并發(fā)數(shù)俱诸,避免因大量的線程之間互相搶占系統(tǒng)資源而導(dǎo)致的阻塞 。
- 能夠?qū)€程進(jìn)行簡(jiǎn)單的管理赊舶,并提供定時(shí)執(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:任務(wù)隊(duì)列睁搭,提交的Runnable對(duì)象存儲(chǔ)在這里。
- keepAliveTime: 非核心線程存活時(shí)間
- unit:keepAliveTime的時(shí)間單位笼平。
- threadFactory:為線程池提供新線程的工廠园骆。
- handler:異常處理策略。
規(guī)則
- 如果此時(shí)線程池中的數(shù)量小于corePoolSize寓调,即使線程池中的線程都處于空閑狀態(tài)锌唾,也要?jiǎng)?chuàng)建新的線程來(lái)處理被添加的任務(wù)。
- 如果此時(shí)線程池中的數(shù)量等于 corePoolSize夺英,但是緩沖隊(duì)列 workQueue未滿晌涕,那么任務(wù)被放入緩沖隊(duì)列。
- 如果此時(shí)線程池中的數(shù)量大于corePoolSize痛悯,緩沖隊(duì)列workQueue滿渐排,并且線程池中的數(shù)量小于maximumPoolSize,建新的線程來(lái)處理被添加的任務(wù)灸蟆。
- 如果此時(shí)線程池中的數(shù)量大于corePoolSize,緩沖隊(duì)列workQueue滿亲族,并且線程池中的數(shù)量等于maximumPoolSize炒考,那么通過(guò) handler所指定的策略來(lái)處理此任務(wù)。