Android的線程和線程池
標簽(空格分隔): android
一些概念:
- 線程分類:主線程和子線程婴梧,主線程主要處理和界面相關(guān)的事情,子線程用于執(zhí)行耗時操作藕筋。
- 如果在主線程即ui線程執(zhí)行耗時操作锅锨,會造成ANR竭鞍,即無法響應(yīng)。
- 一些特殊的線程:AsyncTask(主要用于更新ui)裆熙、IntentService(更方便執(zhí)行后臺任務(wù)端礼,不容易被殺死)、HanderThread入录,AsyncTask底層實現(xiàn)是線程池蛤奥,IntentService、HanderThread底層是線程僚稿。
- 線程池都可以避免因為頻發(fā)創(chuàng)建和摧毀線程帶來的系統(tǒng)開銷凡桥。
一些特殊的線程:
AsyncTask
- 定義:AsyncTask是一種輕量級的異步任務(wù)類,它在線程池中執(zhí)行后臺任務(wù)蚀同,執(zhí)行的進度和最終結(jié)果傳遞給主線程并在主線程中更新ui缅刽。
- AsyncTask的一些方法和參數(shù):
- 參數(shù):Params表示參數(shù)類型,Progress表示后臺任務(wù)執(zhí)行進度的類型唤崭,而Result表示后臺任務(wù)的返回結(jié)果類型拷恨。
- 核心方法:
(1)onPreExecute():在主線程執(zhí)行,可以用于做一些·準備工作谢肾。
(2)doInBackgroud():在線程池執(zhí)行腕侄,此方法執(zhí)行異步任務(wù),params是異步任務(wù)的參數(shù)芦疏,其中的publishProgress方法會調(diào)用onProgressUpdate方法冕杠,此方法返回結(jié)果給onPostExecute方法。
(3)onProgressUpdate 在主線程中執(zhí)行酸茴,后臺任務(wù)的執(zhí)行進度發(fā)生變化此方法會被調(diào)用分预。
(4)onPostExecute 在主線程中執(zhí)行,異步任務(wù)執(zhí)行之后薪捍,此方法會被調(diào)用笼痹。
- 一個簡單的例子:
/*
自定義的一個AsyncTask類
*/
package com.example.windowtest;
import android.os.AsyncTask;
import android.widget.ProgressBar;
import android.widget.TextView;
public class MyAsyncTask extends AsyncTask<Integer,Integer,String> {
private TextView txt;
private ProgressBar pgbar;
public MyAsyncTask(TextView txt,ProgressBar pgbar){
super();
this.txt = txt;
this.pgbar = pgbar;
}
@Override
protected String doInBackground(Integer... integers) {
DelayOperator dop = new DelayOperator();
int i;
for(i=10;i<=100;i+=10){
dop.delay();
publishProgress(i);
}
return i+integers[0].intValue()+"";
}
@Override
protected void onPreExecute() {
super.onPreExecute();
txt.setText("開始執(zhí)行異步線程~");
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
int value = values[0];
pgbar.setProgress(value);
}
}
/*
模擬耗時操作的類
*/
package com.example.windowtest;
public class DelayOperator {
public void delay(){
try{
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
//主線程中調(diào)用代碼
btnupdate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MyAsyncTask myAsyncTask = new MyAsyncTask(txt_title,pgbar);
myAsyncTask.execute(1000);
}
});
運行結(jié)果:

-
AsncTask工作流程
先上一張我手繪的圖:(這字丑的不說了)
AsyncTask
(1)先從execute方法開始,這個方法實際上就是調(diào)用了executeOnExecutor方法酪穿。
(2)這個executeOnExecutor的方法就做了很多的事情凳干,實現(xiàn)一個線程池,同時onPreExecute方法也被執(zhí)行了被济。
(3)關(guān)于sDefaultExecutor線程池救赐,把AsyncTask的params封裝為FutureTask對象,F(xiàn)utureTask對象又交給線程池的execute方法處理只磷。通過判斷線程池中是否有線程執(zhí)行经磅,如果沒有泌绣,執(zhí)行scheduleNext啟動下一個任務(wù)。
(4)實際上AsyncTask有兩個線程池预厌,一個是用來排隊的SerialExecutor用來排隊阿迈,線程池THREAD_POOL_EXECUTOR執(zhí)行真正的任務(wù),而InternalHandler是用來實現(xiàn)將執(zhí)行環(huán)境切換回主線程配乓。
(5)接下來是切換回主線程的邏輯仿滔,調(diào)用mWorker的call方法,執(zhí)行postResult犹芹,該方法的參數(shù)是doInBackground方法的返回結(jié)果崎页,postResult方法會調(diào)用sHandler發(fā)送消息,切回主線程腰埂。
(6)handleMessage會接受兩種msg.what,一種是(1)POST_RESULT飒焦、(2)POST_PROGRESS,(1)消息標識會執(zhí)行Taskfinish方法(任務(wù)被取消執(zhí)行onCancelled方法,任務(wù)沒有被取消就執(zhí)行onPostExecute方法)屿笼,(2)消息標識會執(zhí)行onProgressUpdate方法牺荠。
想到一個問題,AsyncTask任務(wù)是串行還是并行的驴一?
答:android3.0以下版本是并行的休雌,android3.0以上的版本是串行的,
調(diào)用AsyncTask的executeOnExecutor方法任務(wù)會并行肝断。
代碼驗證:
package com.example.asynctaskdemo;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MainActivity extends AppCompatActivity {
private Button start_async,intent_service;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start_async = (Button)findViewById(R.id.start_async_task);
intent_service = (Button)findViewById(R.id.intent_service);
}
public void onClick(View v){
if(v.getId() == R.id.start_async_task){
//串行
new MyAsyncTask("AsyncTask#1").execute("");
new MyAsyncTask("AsyncTask#2").execute("");
new MyAsyncTask("AsyncTask#3").execute("");
new MyAsyncTask("AsyncTask#4").execute("");
}
//并行
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
new MyAsyncTask("AsyncTask#5").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR," ");
new MyAsyncTask("AsyncTask#6").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR," ");
new MyAsyncTask("AsyncTask#7").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR," ");
new MyAsyncTask("AsyncTask#8").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR," ");
}
}else if(v.getId() == R.id.intent_service){
Intent service = new Intent(this,LocalIntentService.class);
service.putExtra("task_action","com.example.action.TASK1");
startService(service);
service.putExtra("task_action","com.example.action.TASK2");
startService(service);
service.putExtra("task_action","com.example.action.TASK3");
startService(service);
}
}
private static class MyAsyncTask extends AsyncTask<String,Integer,String> {
private String mName = "AsyncTask";
private MyAsyncTask(String name){
super();
mName = name;
}
@Override
protected String doInBackground(String... strings) {
try{
Thread.sleep(3000);
}catch (InterruptedException e){
e.printStackTrace();
}
return mName;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Log.e("haha",s+"execute finish at " +df.format(new Date()));
}
}
}


簡單介紹特殊的服務(wù)IntentService
- 簡單介紹:IntentService的優(yōu)先級比一般的線程的優(yōu)先級高杈曲,它特別適合執(zhí)行高優(yōu)先級的后臺任務(wù)。
- 第一次啟動:onCreate方法會被調(diào)用胸懈,onCreate方法會創(chuàng)建HandlerThread担扑,然后他的Looper來構(gòu)建一個Handler對象mServiceHandler,mServiceHandler發(fā)送消息趣钱,執(zhí)行HandlerThread的后臺任務(wù)涌献。
- 每一次啟動IntentService,onStartCommand方法就會調(diào)用一次首有,IntentService在onStartCommand中處理每一個后臺任務(wù)的Intent燕垃。
- 之后的調(diào)用過程:onStart方法--》(發(fā)送一條消息)mServiceHandler--》(傳遞給onHandleIntent)onHandleIntent --》(調(diào)用結(jié)束后)stopSelf()嘗試停止服務(wù)
- stopSelf()是立即停止服務(wù),stopSelf(int startId)是等待所有任務(wù)處理完后停止服務(wù)井联。
- 每執(zhí)行一個后臺任務(wù)就必須啟動一次IntentService利术,而IntentService內(nèi)部則通過消息的方式向HandlerThread請求執(zhí)行任務(wù)。所以IntentService的后臺任務(wù)按順序執(zhí)行低矮。
android中的線程池
三大優(yōu)點
(1)重用線程池中的線程,避免線程創(chuàng)建和線程銷毀帶來的性能開銷
(2)能有效地控制最大的并發(fā)數(shù)被冒,避免大量線程相互搶占資源而導(dǎo)致阻塞現(xiàn)象
(3)能夠簡單地實現(xiàn)線程地管理
配置線程池
public ThreadPoolExecutor(int corePoolSize,//核心線程數(shù)
int maxinumPoolSize,//最大線程數(shù)
long keepAliveTime,//超時時長
TimeUnit unit,//時間單位
BlockingQueue<Runnable> workQueue,//線程池的任務(wù)隊列
ThreadFactory threadFactory//線程工廠)
關(guān)于線程池執(zhí)行任務(wù)的規(guī)律:(自己寫的口訣)
- 核心未滿军掂,開核心轮蜕;核心已滿,插入線程池的隊列蝗锥;隊列已滿跃洛,開普通線程;線程已滿终议,通知調(diào)用者汇竭,拋出異常。
幾種常見的線程池
1穴张、FixedThreadPool
- 全是核心線程细燎,不會被回收
- 沒有超時機制,更快地響應(yīng)外界請求
2皂甘、CachedThreadPool
- 適合于大量耗時較少的任務(wù)
- 只有非核心線程玻驻,有超時機制,會被回收偿枕。
- 無法存儲元素的隊列(空集合)
- 線程數(shù)是一個不定的值璧瞬,非常大,可以認為是一個任意的數(shù)渐夸。
3嗤锉、ScheduledThreadPool
- 執(zhí)行定時任務(wù)和具有固定周期的重復(fù)任務(wù)
- 核心線程是固定的,非核心線程是沒有限制的墓塌,非核心線程閑置時會被回收
4瘟忱、SingleThreadExecutor
- 只有一個核心線程,確保所有任務(wù)在一個線程中順序執(zhí)行桃纯。
- 不需要處理線程同步的問題
private void init(){
Runnable command = new Runnable() {
@Override
public void run() {
SystemClock.sleep(3000);
}
};
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
fixedThreadPool.execute(command);
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
cachedThreadPool.execute(command);
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4);
scheduledThreadPool.schedule(command,2000, TimeUnit.MILLISECONDS);
scheduledThreadPool.scheduleAtFixedRate(command,10,1000,TimeUnit.MILLISECONDS);
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
singleThreadPool.execute(command);
}