Android: 線程相關(guān)知識(shí)點(diǎn)

快速切換到主線程更新UI的三種方法

  • Activity.runOnUiThread(Runnable)
    把更新UI的代碼創(chuàng)建在Runnable中,并傳給 Activity.runOnUiThread()如果當(dāng)前線程是UI線程,那么會(huì)立即執(zhí)行;反之,會(huì)調(diào)用UI線程handler.post()將其放入U(xiǎn)I線程的消息隊(duì)列中
new Thread(){
        public void run() {
        //此時(shí)在子線程
                ((MainActivity) context).runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                        //此時(shí)已經(jīng)回到主線程,注意要強(qiáng)轉(zhuǎn)到主線程的MainActivity
                        }
                });
        };
}.start();
  • View.post(Runnable)
    如果View已經(jīng)attach到Window,直接調(diào)用UI線程的Handler發(fā)送Runnable到MessageQueue
    如果View還未attach到Window,將Runnable放入ViewRootImpl的RunQueue中,RunQueue會(huì)實(shí)現(xiàn)延遲執(zhí)行Runnable任務(wù),并且Runnable最終不會(huì)被加入到MessageQueue里,也不會(huì)被Looper執(zhí)行,而是等到ViewRootImpl的下一個(gè)performTraversals時(shí)候,把RunQueue里的所有Runnable都拿出來并執(zhí)行,接著清空RunQueue
mTextView.post(new Runnable() {
        @Override
        //可快速更新該view
        public void run() {
                mTextView.setText("xxx");
        //也可以更新其他view
        mIageView.setBackgroundResource(R.drawable.icon);
        }
});

還有View.postDelayed(Runnable, long),其中l(wèi)ong表示延遲的毫秒數(shù),示例如下。

//5秒倒計(jì)時(shí)跳轉(zhuǎn)到下個(gè)頁面
index=5;
mTextView.postDelayed(new Runnable() {
        @Override
        public void run() {
                mTextView.setText("" + index);
                index--;
                if (index == 0) {
                        Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(intent);
                } else {
                        mTextView.postDelayed(this, 1000);
                }
        }
}, 1000);

c.Handler.post(Runnable)&Handler.post(Runnable,long)

//假設(shè)在子線程,需要獲取主線程的Looper和Queue
new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
                //此時(shí)已經(jīng)回到主線程
        }
});

當(dāng)然還可以用AsyncTask、IntentService、HandlerThread,還有許多開源框架。

Thread阻塞方式:

  • sleep():
    進(jìn)入休眠狀態(tài),但持有對(duì)象的鎖旗標(biāo),休眠結(jié)束后,從阻塞狀態(tài)——》就緒狀態(tài)。

  • yield():
    進(jìn)入休眠狀態(tài),也持有對(duì)象的鎖旗標(biāo)和sleep相似,但是不能控制時(shí)間,也有可能剛放棄運(yùn)行就重新獲取運(yùn)行權(quán)。

  • wait():
    釋放鎖旗標(biāo),進(jìn)入wait池,等到另一個(gè)線程對(duì)等待的對(duì)象調(diào)用notify()或notifyall()后,等待線程才會(huì)從wait池進(jìn)入lock池(從一種阻塞狀態(tài)進(jìn)入另一種阻塞狀態(tài))。

  • synchornized未獲取對(duì)象的鎖旗標(biāo)
    進(jìn)入該對(duì)象lock池,等待鎖旗標(biāo)被歸還,該對(duì)象的lock池中的線程才會(huì)獲得鎖旗標(biāo)進(jìn)入就緒狀態(tài)。

  • Threa中的isAlive(),與線程狀態(tài)有關(guān)。
    線程啟動(dòng)后,并且在run()方法沒有結(jié)束前,isAlive返回true。
    所以如果返回false,就知道該線程處于剛被創(chuàng)建還尚未處于strat階段,或者已處于dead狀態(tài)。
    如果返回true,該線程就處于其生命周期中(運(yùn)行或阻塞)。

線程狀態(tài)流程圖

java_thread_state.png
  • NEW:創(chuàng)建狀態(tài),線程創(chuàng)建之后,但是還未啟動(dòng)。
  • RUNNABLE:運(yùn)行狀態(tài),處于運(yùn)行狀態(tài)的線程,但有可能處于等待狀態(tài),例如等待CPU、IO等。
  • WAITING:等待狀態(tài),一般是調(diào)用了wait()、join()、LockSupport.spark()等方法。
  • TIMED_WAITING:超時(shí)等待狀態(tài),也就是帶時(shí)間的等待狀態(tài)。一般是調(diào)用了wait(time)、join(time)、LockSupport.sparkNanos()、LockSupport.sparkUnit()等方法。
  • BLOCKED:阻塞狀態(tài),等待鎖的釋放,例如調(diào)用了synchronized增加了鎖。
  • TERMINATED:終止?fàn)顟B(tài),一般是線程完成任務(wù)后退出或者異常終止。

NEW、WAITING、TIMED_WAITING都比較好理解,我們重點(diǎn)說一說RUNNABLE運(yùn)行態(tài)和BLOCKED阻塞態(tài)。

線程進(jìn)入RUNNABLE運(yùn)行態(tài)一般分為五種情況:

  • 線程調(diào)用sleep(time)后查出了休眠時(shí)間
  • 線程調(diào)用的阻塞IO已經(jīng)返回,阻塞方法執(zhí)行完畢
  • 線程成功的獲取了資源鎖
  • 線程正在等待某個(gè)通知,成功的獲得了其他線程發(fā)出的通知
  • 線程處于掛起狀態(tài),然后調(diào)用了resume()恢復(fù)方法,解除了掛起。

線程進(jìn)入BLOCKED阻塞態(tài)一般也分為五種情況:

  • 線程調(diào)用sleep()方法主動(dòng)放棄占有的資源
  • 線程調(diào)用了阻塞式IO的方法,在該方法返回前,該線程被阻塞。
  • 線程視圖獲得一個(gè)資源鎖,但是該資源鎖正被其他線程鎖持有。
  • 線程正在等待某個(gè)通知
  • 線程調(diào)度器調(diào)用suspend()方法將該線程掛起

我們?cè)賮砜纯春途€程狀態(tài)相關(guān)的一些方法。

  • sleep()方法讓當(dāng)前正在執(zhí)行的線程在指定時(shí)間內(nèi)暫停執(zhí)行,正在執(zhí)行的線程可以通過Thread.currentThread()方法獲取。
  • yield()方法放棄線程持有的CPU資源,將其讓給其他任務(wù)去占用CPU執(zhí)行時(shí)間。但放棄的時(shí)間不確定,有可能剛剛放棄,馬上又獲得CPU時(shí)間片。
  • wait()方法是當(dāng)前執(zhí)行代碼的線程進(jìn)行等待,將當(dāng)前線程放入預(yù)執(zhí)行隊(duì)列,并在wait()所在的代碼處停止執(zhí)行,知道接到通知或者被中斷為止。該方法可以使得調(diào)用該方法的線程釋放共享資源的鎖, 然后從運(yùn)行狀態(tài)退出,進(jìn)入等待隊(duì)列,直到再次被喚醒。該方法只能在同步代碼塊里調(diào)用,否則會(huì)拋出IllegalMonitorStateException異常。wait(long millis)方法等待某一段時(shí)間內(nèi)是否有線程對(duì)鎖進(jìn)行喚醒,如果超過了這個(gè)時(shí)間則自動(dòng)喚醒。
  • notify()方法用來通知那些可能等待該對(duì)象的對(duì)象鎖的其他線程,該方法可以隨機(jī)喚醒等待隊(duì)列中等同一共享資源的一個(gè)線程,并使該線程退出等待隊(duì)列,進(jìn)入可運(yùn)行狀態(tài)。
  • notifyAll()方法可以是所有正在等待隊(duì)列中等待同一共享資源的全部線程從等待狀態(tài)退出,進(jìn)入可運(yùn)行狀態(tài),一般會(huì)是優(yōu)先級(jí)高的線程先執(zhí)行,但是根據(jù)虛擬機(jī)的實(shí)現(xiàn)不同,也有可能是隨機(jī)執(zhí)行。
  • join()方法可以讓調(diào)用它的線程正常執(zhí)行完成后,再去執(zhí)行該線程后面的代碼,它具有讓線程排隊(duì)的作用。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 線程基本知識(shí) 什么是線程安全性?當(dāng)多個(gè)線程訪問某個(gè)類時(shí),這個(gè)類始終都能表現(xiàn)出正確的行為,那么可以認(rèn)為這個(gè)類是線程安...
    Cheava閱讀 1,106評(píng)論 0 1
  • 線程的狀態(tài)Thread.yield()是使得線程從新變?yōu)榫途w狀態(tài)從新和其他就緒線程競爭cpu,有可能下次還是他運(yùn)行...
    簡書徐小耳閱讀 162評(píng)論 0 0
  • 0.Android手機(jī)操作系統(tǒng)的四層架構(gòu)? Applications , Application Framewor...
    lucas777閱讀 8,173評(píng)論 0 16
  • 別人的總結(jié)不一定適合自己,所以盡量多做一些自己的總結(jié),針對(duì)自己的薄弱點(diǎn)重點(diǎn)說明,適當(dāng)?shù)慕梃b別人,少走一些彎路。最重...
    renkuo閱讀 7,612評(píng)論 2 48
  • 年后上班的日子才是真的作息不規(guī)律! 晚上不睡,早晨不起! 真不像在家里那么正常,早睡早起,一日三餐家人定點(diǎn)叫我,不...
    趙小秋秋秋閱讀 258評(píng)論 0 0

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