Android 的線程和線程池

Android 的線程分為主線程和子線程。

  • 主線程
    更新 UI

  • 子線程
    執(zhí)行耗時操作

  • AsyncTask
    封裝了線程池和 Handler,主要為了方便在子線程中更新 UI。

  • IntentService
    一個服務(wù),系統(tǒng)對其進(jìn)行了封裝,IntentService 內(nèi)部采用 HandlerThread 來執(zhí)行任務(wù),執(zhí)行完會自動退出。

  • HandlerThread
    一種具有消息循環(huán)的線程,它的內(nèi)部可以使用 Handler。

在操作系統(tǒng)中,線程是操作系統(tǒng)調(diào)度的最小單元,線程的創(chuàng)建和銷毀都會有相應(yīng)的開銷。線程池可以緩存一定數(shù)量的線程,通過線程池可以避免頻繁創(chuàng)建和銷毀線程造成的開銷。

11.1 主線程和子線程


默認(rèn)一個進(jìn)程中只有一個主線程,其他都是子線程。

11.2 Android 中的線程形態(tài)


11.2.1 AsyncTask

public abstract class AsyncTask<Params, Progress, Result> 
  • onPreExecute:在主線程執(zhí)行,在異步任務(wù)執(zhí)行之前被調(diào)用

  • doInBackground:在線程池中執(zhí)行,用于執(zhí)行異步任務(wù),params 表示異步任務(wù)輸入的參數(shù),可以通過 publishProgress 方法調(diào)用 onProgressUpdate 方法來更新進(jìn)度條。

  • onProgressUpdate:在主線程執(zhí)行,當(dāng)后臺任務(wù)的執(zhí)行進(jìn)度發(fā)生改變時調(diào)用;

  • onPreExecute:在主線程執(zhí)行,異步任務(wù)執(zhí)行后調(diào)用,result 是doInBackground 的返回值。

AsyncTask 在具體的使用過程中也是有一些條件限制的,主要有如下幾點(diǎn):
(1)AysncTask 的類必須在主線程中加載,這就意味著第一次訪問 AsyncTask 必須在主線程,這個過程在 Android 4.0以上已經(jīng)被系統(tǒng)自動完成了。
(2)AsyncTask 的對象必須在主線程中創(chuàng)建。
(3)execute 方法必須在 UI 線程調(diào)用。
(4)不要在程序中直接調(diào)用 onPreExecute、onPreExecute、doInBackground、onProgressUpdate 方法。
(5)一個 AsyncTask 對象只能執(zhí)行一次,即只能調(diào)用一次 execute 方法,否則會報運(yùn)行時異常。
(6)Android 3.0 開始,AsyncTask 采用一個線程來執(zhí)行串行任務(wù)。

GIF.gif
    public void click(View view) {
        new MyAsyncTask("1 號").execute();
        new MyAsyncTask("2 號").execute();
        new MyAsyncTask("3 號").execute();
        new MyAsyncTask("4 號").execute();
        new MyAsyncTask("5 號").execute();
        new MyAsyncTask("6 號").execute();
}
    private static class MyAsyncTask extends AsyncTask<String, Integer, String> {

        public String mName = "AsyncTask";

        public MyAsyncTask(String name) {
            super();
            mName = name;
        }

        @Override
        protected String doInBackground(String... params) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return mName;
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            Log.d(TAG, s);
        }
    }

11.2.4 IntentService

IntentService 處理后臺任務(wù)是排隊(duì)執(zhí)行的,執(zhí)行順序就是發(fā)起請求的順序。

GIF.gif

IntentService 繼承 Service,所以它能夠運(yùn)行在后臺。

public class LocalIntentService extends IntentService {

    public static final String TAG = "LocalIntentService";

    public LocalIntentService() {
        super(TAG);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        String action = intent.getStringExtra("task_action");
        Log.d(TAG, "receive task: " + action);
        SystemClock.sleep(500);
        if ("com.kjn.action.TASK1".equals(action)) {
            Log.d(TAG, "handle task: " + action);
        }
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "service destroyed.");
        super.onDestroy();
    }
}

點(diǎn)擊事件

public void click(View view) {
        if (view.getId() == R.id.btn1) {
        start(this,"com.kjn.action.TASK1");
        start(this,"com.kjn.action.TASK2");
        start(this,"com.kjn.action.TASK3");
        } else if (view.getId() == R.id.btn2) {
            Intent intent = new Intent(MainActivity.this, SecondActivity.class);
            startActivity(intent);
        }
    }
 public static void start(Context context,String action) {
        Intent starter = new Intent(context, LocalIntentService.class);
        starter.putExtra("task_action",action);
        context.startService(starter);
    }

11.3 Android 中的線程池

Android 中的線程池都是直接或者間接通過配置 ThreadPoolExecutor 來實(shí)現(xiàn)的。

線程池的優(yōu)點(diǎn):

(1)重用線程池中的線程,避免因?yàn)榫€程的創(chuàng)建和銷毀所帶來的性能開銷。

(2)能有效控制線程池的最大并發(fā)數(shù),避免大量的線程之間因互相搶占系統(tǒng)資源而導(dǎo)致的阻塞現(xiàn)象。

(3)能夠?qū)€程進(jìn)行簡單的管理,并提供定時執(zhí)行以及指定間隔循環(huán)執(zhí)行等功能。

11.3.1 ThreadPoolExecutor

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory)
  • corePoolSize:

線程池的核心線程數(shù),默認(rèn)情況下,核心線程會在線程池中一直存活,如果將 ThreadPoolExecutor 的 allowCoreThreadTimeOut 屬性設(shè)置為 true,那么閑置的核心線程在等待新任務(wù)到來時會有超時策略,這個時間間隔由 keepAliveTime 所指定,,當(dāng)?shù)却龝r間超過 keepAliveTime 所指定的時長后,核心線程就會被終止。

  • maximumPoolSize:

線程池所能容納的最大線程數(shù),超出后,后續(xù)的新任務(wù)會被阻塞。

  • keepAliveTime:

非核心線程閑置時的超時時長,超過這個時長,非核心線程就會被回收。當(dāng) ThreadPoolExecutor 的 allowCoreThreadTimeOut 屬性設(shè)置為 true時,同樣作用于核心線程。

  • unit:用于指定 keepAliveTime 參數(shù)的時間單位這是一個枚舉,常用的有:

  • TimeUnit.MILLISECONDS:毫秒

  • TimeUnit.SECONDS:秒

  • TimeUnit.MINUTES:分鐘

  • workQueue:

線程池中的任務(wù)隊(duì)列,通過 execute 方法提交的 Runnable 對象會存儲在這個參數(shù)中。

  • threadFactory:

線程工廠,為線程池提供創(chuàng)建新線程的功能,ThreadFactory 是一個接口,它只有一個方法: Thread newThread(Runnable r);

ThreadPoolExecutor 執(zhí)行任務(wù)時大致遵循如下規(guī)則:

(1)如果線程池中的線程數(shù)量未達(dá)到核心線程的數(shù)量,那么會直接啟動一個核心線程來執(zhí)行任務(wù)。

(2)如果線程池中的線程數(shù)量已經(jīng)達(dá)到了或者超過了核心線程的數(shù)量,那么任務(wù)會被插入到任務(wù)隊(duì)列中排隊(duì)等待執(zhí)行。

(3)如果在步驟(2)中無法將任務(wù)插入到任務(wù)隊(duì)列中,這往往是由于任務(wù)隊(duì)列已滿,這個時候如果線程數(shù)量未達(dá)到線程池規(guī)定的最大值,那么會立刻啟動一個非核心線程來執(zhí)行任務(wù)。

(4)如果步驟(3)中線程數(shù)量已經(jīng)達(dá)到線程池規(guī)定的最大值,那么就拒絕執(zhí)行任務(wù),ThreadPoolExecutor 會調(diào)用 RejectedExecutionHandler 的 rejectedExecution 方法來通知調(diào)用者。

配置參看 AsyncTask :

public abstract class AsyncTask<Params, Progress, Result> {
    private static final String LOG_TAG = "AsyncTask";
    // CPU 數(shù)量
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    // 最大線程數(shù) CPU 數(shù)量 +1
    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
    // 線程池的最大線程數(shù)為核心數(shù)的 2 倍 +1;
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    // 超時時間為 1 秒
    private static final int KEEP_ALIVE = 1;

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };
    // 任務(wù)隊(duì)列的容量為 128。
    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
  • 核心線程數(shù)等于 CPU 核心數(shù) +1;

  • 線程池的最大線程數(shù)為核心數(shù)的 2 倍 +1;

  • 核心線程無超時機(jī)制,非核心線程在閑置時的超時時間為 1 秒;

  • 任務(wù)隊(duì)列的容量為 128。

11.3.2 線程池的分類

常見的有四類線程池:

(1)FixedThreadPool:

它是一種只有核心線程并且線程數(shù)量固定的線程池,他們不會被回收,除非線程池被關(guān)閉了。因?yàn)槭呛诵木€程,它能更加快速地響應(yīng)外界的請求,沒有超時機(jī)制,任務(wù)隊(duì)列也沒有大小限制。

    Runnable command = new Runnable() {
        @Override
        public void run() {
            SystemClock.sleep(2000);
        }
    };
    // 通過 Executors 的 newFixedThreadPool 方法來創(chuàng)建。
    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
    fixedThreadPool.execute(command);
public class Executors {
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
...

(2)CachedThreadPool

核心線程為 0 ,最大線程數(shù)為 Integer.MAX_VALUE,所以它只有非核心線程,超時時長為 60 秒,超過 60 秒閑置就會被回收。CachedThreadPool 的任務(wù)隊(duì)列相當(dāng)于一個空集合,這將導(dǎo)致任何任務(wù)都會立即被執(zhí)行。CachedThreadPool 比較適合執(zhí)行大量的耗時較少的任務(wù),當(dāng)閑置時,線程池中的線程都會因?yàn)槌瑫r而被停止,這時它幾乎不占用任何系統(tǒng)資源。

 ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
 cachedThreadPool.execute(command);
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

(3)ScheduledThreadPool

它的核心線程數(shù)是固定的,非核心線程數(shù) Integer.MAX_VALUE,超時時間 0 ,閑置就會直接回收非核心線程,這類線程主要用于執(zhí)行定時任務(wù)和具有固定周期的重復(fù)任務(wù)。

 ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4);
 // 2000ms后執(zhí)行command
 scheduledThreadPool.schedule(command, 2000, TimeUnit.MILLISECONDS);
 // 延遲10ms后,每隔1000ms執(zhí)行一次command
 scheduledThreadPool.scheduleAtFixedRate(command, 10, 1000, TimeUnit.MILLISECONDS);
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
    // super 調(diào)用構(gòu)造方法
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

(4)SingleThreadExecutor

這類線程池內(nèi)部只有一個核心線程,它確保所有的任務(wù)都在同一個線程中按順序執(zhí)行,這使得這些任務(wù)之間不需要處理線程同步的問題。

 ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
 singleThreadExecutor.execute(command);
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

本章源碼:https://github.com/singwhatiwanna/android-art-res/tree/master/Chapter_11

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

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

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