Android的線程和線程池

Android的線程和線程池

標(biāo)簽(空格分隔): 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
    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)消息標(biāo)識會執(zhí)行Taskfinish方法(任務(wù)被取消執(zhí)行onCancelled方法,任務(wù)沒有被取消就執(zhí)行onPostExecute方法),(2)消息標(biāo)識會執(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()));
        }
    }
}

AsyncTask串行
AsyncTask串行
AsyncTask并行
AsyncTask并行

簡單介紹特殊的服務(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);
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 從用途上來說,線程分為主線程和子線程,主線程主要處理和界面相關(guān)的事情,子線程則往往用于執(zhí)行耗時操作。 除了Thre...
    小柏不是大白閱讀 708評論 0 3
  • 線程 線程在Android中是一個很重要的概念,從用途上來說,線程分為主線程和子線程,主線程主要處理和界面相關(guān)的事...
    12313凱皇閱讀 1,452評論 0 1
  • 線程分為主線程和子線程,主線程主要處理和界面相關(guān)的事情,而子線程則往往用于執(zhí)行耗時操作。 AsyncTask封裝了...
    Tom_Ji閱讀 514評論 0 5
  • Android中可以扮演線程的角色還有很多,比如AsyncTask和IntentService,同時Handler...
    空白_c46e閱讀 395評論 0 2
  • 春節(jié)假期,幾點感悟心得分享一下。 1-閱讀的收獲:讀了樊登老師的【讀書是一輩子的事情】第一部份認識自己,這是很多書...
    風(fēng)之吻Sam閱讀 221評論 0 4

友情鏈接更多精彩內(nèi)容