溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Android中的線程和線程池有什么作用

發(fā)布時(shí)間:2022-12-28 15:05:08 來源:億速云 閱讀:83 作者:iii 欄目:開發(fā)技術(shù)

今天小編給大家分享一下Android中的線程和線程池有什么作用的相關(guān)知識點(diǎn),內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

    前言

    從用途上來說Android的線程主要分為主線程和子線程兩類,主線程主要處理和界面相關(guān)的工作,子線程主要處理耗時(shí)操作。除Thread之外,Android中還有其他扮演線程的角色如AsyncTask、IntentService、HandleThread,其中AsyncTask的底層用到了線程池,IntentService和HandleThread的底層直接使用了線程。

    AsyncTask內(nèi)部封裝了線程池和Handler主要是為了方便開發(fā)者在在線程中更新UI;HandlerThread是一個(gè)具有消息循環(huán)的線程,它的內(nèi)部可以使用Handler;IntentService是一個(gè)服務(wù),系統(tǒng)對其進(jìn)行了封裝使其可以更方便的執(zhí)行后臺任務(wù),IntentService內(nèi)部采用HandleThread來執(zhí)行任務(wù),當(dāng)任務(wù)執(zhí)行完畢后IntentService會自動(dòng)退出。IntentService是一個(gè)服務(wù)但是它不容易被系統(tǒng)殺死因此它可以盡量的保證任務(wù)的執(zhí)行。

    1.主線程和子線程

    主線程是指進(jìn)程所擁有的的線程,在Java中默認(rèn)情況下一個(gè)進(jìn)程只能有一個(gè)線程,這個(gè)線程就是主線程。主線程主要處理界面交互的相關(guān)邏輯,因?yàn)榻缑骐S時(shí)都有可能更新因此在主線程不能做耗時(shí)操作,否則界面就會出現(xiàn)卡頓的現(xiàn)象。主線程之外的線程都是子線程,也叫做工作線程。

    Android沿用了Java的線程模型,也有主線程和子線程之分,主線程主要工作是運(yùn)行四大組件及處理他們和用戶的交互,子線程的主要工作就是處理耗時(shí)任務(wù),例如網(wǎng)絡(luò)請求,I/O操作等。Android3.0開始系統(tǒng)要求網(wǎng)絡(luò)訪問必須在子線程中進(jìn)行否則就會報(bào)錯(cuò),NetWorkOnMainThreadException

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

    2.1 AsyncTask

    AsyncTask是一個(gè)輕量級的異步任務(wù)類,它可以在線程池中執(zhí)行異步任務(wù)然后把執(zhí)行進(jìn)度和執(zhí)行結(jié)果傳遞給主線程并在主線程更新UI。從實(shí)現(xiàn)上來說AsyncTask封裝了Thread和Handler,通過AsyncTask可以很方便的執(zhí)行后臺任務(wù)以及主線程中訪問UI,但是AsyncTask不適合處理耗時(shí)任務(wù),耗時(shí)任務(wù)還是要交給線程池執(zhí)行。

    AsyncTask的四個(gè)核心類如下:


      • onPreExecute():主要用于做一些準(zhǔn)備工作,在主線程中執(zhí)行異步任務(wù)執(zhí)行之前

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

      • onProgressUpdate(Progress .. value):在主線程執(zhí)行,當(dāng)任務(wù)執(zhí)行進(jìn)度發(fā)生改變時(shí)會調(diào)用這個(gè)方法

      • onPostExecute(Result result):在主線程執(zhí)行,異步任務(wù)之后執(zhí)行這個(gè)方法,result參數(shù)是返回值,即doInBackground的返回值。

    2.2 AsyncTask的工作原理

    2.3 HandleThread

    HandleThread繼承自Thread,它是一種可以使用Handler的Thread,它的實(shí)現(xiàn)在run方法中調(diào)用Looper.prepare()來創(chuàng)建消息隊(duì)列然后通過Looper.loop()來開啟消息循環(huán),這樣在實(shí)際使用中就可以在HandleThread中創(chuàng)建Handler了。

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

    HandleThread和Thread的區(qū)別是什么?


      • Thread的run方法中主要是用來執(zhí)行一個(gè)耗時(shí)任務(wù);

      • HandleThread在內(nèi)部創(chuàng)建了一個(gè)消息隊(duì)列需要通過Handler的消息方式來通知HandleThread執(zhí)行一個(gè)具體的任務(wù),HandlerThread的run方法是一個(gè)無限循環(huán)因此在不使用是調(diào)用quit或者quitSafely方法終止線程的執(zhí)行。HandleTread的具體使用場景是IntentService。

    2.4 IntentService

    IntentService繼承自Service并且是一個(gè)抽象的類因此使用它時(shí)就必須創(chuàng)建它的子類,IntentService可用于執(zhí)行后臺耗時(shí)的任務(wù),當(dāng)任務(wù)執(zhí)行完畢后就會自動(dòng)停止。IntentService是一個(gè)服務(wù)因此它的優(yōu)先級要比線程高并且不容易被系統(tǒng)殺死,因此可以利用這個(gè)特點(diǎn)執(zhí)行一些高優(yōu)先級的后臺任務(wù),它的實(shí)現(xiàn)主要是HandlerThread和Handler,這點(diǎn)可以從onCreate方法中了解。

    //IntentService#onCreate
    @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);
    }

    當(dāng)IntentService第一次被啟動(dòng)時(shí)回調(diào)用onCreate方法,在onCreate方法中會創(chuàng)建HandlerThread,然后使用它的Looper創(chuàng)建一個(gè)Handler對象ServiceHandler,這樣通過mServiceHandler把消息發(fā)送到HandlerThread中執(zhí)行。每次啟動(dòng)IntentService都會調(diào)用onStartCommand,IntentService在onStartCommand中會處理每個(gè)后臺任務(wù)的Intent。

    //IntentService#onStartCommand
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }
    
    //IntentService#onStart
    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }
    
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }
    
        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

    onStartCommand是如何處理外界的Intent的?

    在onStartCommand方法中進(jìn)入了onStart方法,在這個(gè)方法中IntentService通過mserviceHandler發(fā)送了一條消息,然后這個(gè)消息會在HandlerThread中被處理。mServiceHandler接收到消息后會把intent傳遞給onHandlerIntent(),這個(gè)intent跟啟動(dòng)IntentService時(shí)的startService中的intent是一樣的,因此可以通過這個(gè)intent解析出啟動(dòng)IntentService傳遞的參數(shù)是什么然后通過這些參數(shù)就可以區(qū)分具體的后臺任務(wù),這樣onHandleIntent就可以對不同的后臺任務(wù)做處理了。當(dāng)onHandleIntent方法執(zhí)行結(jié)束后IntentService就會通過stopSelf(int startId)方法來嘗試停止服務(wù),這里不用stopSelf()的原因是因?yàn)檫@個(gè)方法被調(diào)用之后會立即停止服務(wù)但是這個(gè)時(shí)候可能還有其他消息未處理完畢,而采用stopSelf(int startId)方法則會等待所有消息都處理完畢后才會終止服務(wù)。調(diào)用stopSelf(int startId)終止服務(wù)時(shí)會根據(jù)startId判斷最近啟動(dòng)的服務(wù)的startId是否相等,相等則立即終止服務(wù)否則不終止服務(wù)。

    每執(zhí)行一個(gè)后臺任務(wù)就會啟動(dòng)一次intentService,而IntentService內(nèi)部則通過消息的方式向HandlerThread請求執(zhí)行任務(wù),Handler中的Looper是順序處理消息的,這就意味著IntentService也是順序執(zhí)行后臺任務(wù)的,當(dāng)有多個(gè)后臺任務(wù)同時(shí)存在時(shí)這些后臺任務(wù)會按照外界發(fā)起的順序排隊(duì)執(zhí)行。

    3.Android中的線程池

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


      • 線程池中的線程可重復(fù)使用,避免因?yàn)榫€程的創(chuàng)建和銷毀帶來的性能開銷;

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

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

    Android的線程池的概念來自于Java中的Executor,Executor是一個(gè)接口,真正的線程的實(shí)現(xiàn)是ThreadPoolExecutor,它提供了一些列參數(shù)來配置線程池,通過不同的參數(shù)可以創(chuàng)建不同的線程池。

    3.1 ThreadPoolExecutor

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

    ThreadPoolExecutor是線程池的真正實(shí)現(xiàn),它的構(gòu)造函數(shù)中提供了一系列參數(shù),先看一下每個(gè)參數(shù)的含義:


      • corePoolSize:線程池的核心線程數(shù),默認(rèn)情況下核心線程會在線程池中一直存活即使他們處于閑置狀態(tài)。如果將ThreadPoolExecutor的allowCoreThreadTimeOut置為true那么閑置的核心線程在等待新的任務(wù)到來時(shí)會有超時(shí)策略,超時(shí)時(shí)間由keepAliveTime指定,當(dāng)?shù)却龝r(shí)間超過keepAliveTime設(shè)置的時(shí)間后核心線程就會被終止。

      • maxinumPoolSize:線程池中所能容納的最大線程數(shù),當(dāng)活動(dòng)線程達(dá)到做大數(shù)量時(shí)后續(xù)的新任務(wù)就會被阻塞。

      • keepAliveTime:非核心線程閑置時(shí)的超時(shí)時(shí)長,超過這個(gè)時(shí)長非核心線程就會被回收。

      • unit:用于指定超時(shí)時(shí)間的單位,常用單位有毫秒、秒、分鐘等。

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

      • threadFactory:線程工廠,為線程池提供創(chuàng)建新的線程的功能。

      • handler:這個(gè)參數(shù)不常用,當(dāng)線程池?zé)o法執(zhí)行新的任務(wù)時(shí),這可能是由于任務(wù)隊(duì)列已滿或者無法成功執(zhí)行任務(wù),這個(gè)時(shí)候ThreadPoolExecutor會調(diào)用handler的rejectExecution方法來通知調(diào)用者。

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

    • 如果線程池中的線程數(shù)量沒有達(dá)到核心線程的數(shù)量那么會直接啟動(dòng)一個(gè)核心線程來執(zhí)行任務(wù);

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

      如果任務(wù)隊(duì)列也無法插入那么在基本可以確定是隊(duì)列已滿這時(shí)如果線程池中的線程數(shù)量沒有達(dá)到最大值就會立刻創(chuàng)建非核心線程來執(zhí)行任務(wù);

      如果非核心線程的創(chuàng)建已經(jīng)達(dá)到或者超過線程池的最大數(shù)量那么就拒絕執(zhí)行此任務(wù),同時(shí)ThreadPoolExecutor會通過RejectedExecutionHandler拋出異常rejectedExecution。

    3.2線程池的分類

    • FixedThreadPool:它是一種數(shù)量固定的線程池,當(dāng)線程處于空閑狀態(tài)時(shí)也不會被回收,除非線程池被關(guān)閉。當(dāng)所有的線程都處于活動(dòng)狀態(tài)時(shí),新任務(wù)都會處于等待狀態(tài),直到有空閑線程出來。FixedThreadPool只有核心線程并且不會被回收因此它可以更加快速的響應(yīng)外界的請求。

    • CacheThreadPool:它是一種線程數(shù)量不定的線程池且只有非核心線程,線程的最大數(shù)量是Integer.MAX_VALUE,當(dāng)線程池中的線程都處于活動(dòng)狀態(tài)時(shí)如果有新的任務(wù)進(jìn)來就會創(chuàng)建一個(gè)新的線程去執(zhí)行任務(wù),同時(shí)它還有超時(shí)機(jī)制,當(dāng)一個(gè)線程閑置超過60秒時(shí)就會被回收。

    • ScheduleThreadPool:它是一種擁有固定數(shù)量的核心線程和不固定數(shù)量的非核心線程的線程池,當(dāng)非核心線程閑置時(shí)會立即被回收。

    • SignleThreadExecutor:它是一種只有一個(gè)核心線程的線程池,所有任務(wù)都在同一個(gè)線程中按順序執(zhí)行。

    以上就是“Android中的線程和線程池有什么作用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學(xué)習(xí)更多的知識,請關(guān)注億速云行業(yè)資訊頻道。

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI