剖析Android中程式與執行緒排程之nice
在計算機作業系統中,程式是進行資源分配和排程的基本單位,同時每個程式之內也可以存在多個執行緒。那麼在Android系統(Linux Kernel)中,程式是如何去搶佔資源,執行緒又是如何根據優先順序切換呢,本文將嘗試剖析這個問題,研究nice在Linux以及Android系統中的應用。
一些概念
- 程式 是計算機系統中,程式執行的實體,也是執行緒的容器。
- 執行緒 是程式中實際執行單位,一個執行緒是程式執行流的最小單元。在一個程式中可以有多個執行緒存在。
nice與程式排程
Linux中,使用nice value(以下成為nice值)來設定一個程式的優先順序,系統任務排程器根據nice值合理安排排程。
- nice的取值範圍為-20到19。
- 通常情況下,nice的預設值為0。視具體作業系統而定。
- nice的值越大,程式的優先順序就越低,獲得CPU呼叫的機會越少,nice值越小,程式的優先順序則越高,獲得CPU呼叫的機會越多。
- 一個nice值為-20的程式優先順序最高,nice值為19的程式優先順序最低。
- 父程式fork出來的子程式nice值與父程式相同。父程式renice,子程式nice值不會隨之改變。
詞源考究
nice這個命令的來源幾乎沒有資料提到,於是便嘗試自己來推斷一下。在諸如詞霸,滬江等詞典給出的意思均為好的;美好的;可愛的;好心的,友好的。而有道詞典則稍微給出了一個其他詞典沒有的和藹的。個人認為有道給出的這個比較合理。要想做到和藹,就需要做到謙讓,因此或多或少犧牲自己一點,成全他人。所以nice值越高,越和藹,但是自己的優先順序也會越低。
renice
對於一個新的程式我們可以按照下面的程式碼為一個程式設定nice值。
nice -n 10 adb logcat
對於已經建立的程式,我們可以使用renice來修改nice值
sudo renice -n 0 -p 24161
該命令需要使用root許可權,-p對應的值為程式id。
注意renice命令在Linux發行版中-n 的值應該為程式的目標優先順序。而Mac下-n,則是代表對當前許可權的增加值。 比如在Mac下,講一個程式的nice值由19改成10,可以這樣操作sudo renice -n -9 -p 24161,這一點需要注意,避免掉進坑裡。
Android中的nice
由於Android基於Linux Kernel,在Android中也存在nice值。但是一般情況下我們無法控制,原因如下:
- Android系統並不像其他Linux發行版那樣便捷地使用nice命令操作。
- renice需要root許可權,一般應用無法實現。
執行緒排程
雖然對於程式的優先順序,我們無法控制,但是我們可以控制程式中的執行緒的優先順序。在Android中有兩種執行緒的優先順序,一種為Android API版本,另一種是 Java 原生版本。
Android API
Android中的執行緒優先順序別目前規定了如下,瞭解了程式優先順序與nice值的關係,那麼執行緒優先順序與值之間的關係也就更加容易理解。
- THREAD_PRIORITY_DEFAULT,預設的執行緒優先順序,值為0。
- THREAD_PRIORITY_LOWEST,最低的執行緒級別,值為19。
- THREAD_PRIORITY_BACKGROUND 後臺執行緒建議設定這個優先順序,值為10。
- THREAD_PRIORITY_FOREGROUND 使用者正在互動的UI執行緒,程式碼中無法設定該優先順序,系統會按照情況調整到該優先順序,值為-2。
- THREAD_PRIORITY_DISPLAY 也是與UI互動相關的優先順序界別,但是要比THREAD_PRIORITY_FOREGROUND優先,程式碼中無法設定,由系統按照情況調整,值為-4。
- THREAD_PRIORITY_URGENT_DISPLAY 顯示執行緒的最高階別,用來處理繪製畫面和檢索輸入事件,程式碼中無法設定成該優先順序。值為-8。
- THREAD_PRIORITY_AUDIO 聲音執行緒的標準級別,程式碼中無法設定為該優先順序,值為 -16。
- THREAD_PRIORITY_URGENT_AUDIO 聲音執行緒的最高階別,優先程度較THREAD_PRIORITY_AUDIO要高。程式碼中無法設定為該優先順序。值為-19。
- THREAD_PRIORITY_MORE_FAVORABLE 相對THREAD_PRIORITY_DEFAULT稍微優先,值為-1。
- THREAD_PRIORITY_LESS_FAVORABLE 相對THREAD_PRIORITY_DEFAULT稍微落後一些,值為1。
使用Android API為執行緒設定優先順序也很簡單,只需要線上程執行時呼叫android.os.Process.setThreadPriority方法即可。這種線上程執行時進行修改優先順序,效果類似renice。
new Thread () { @Override public void run() { super.run(); android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } }.start();
Java原生API
Java為Thread提供了三個級別的設定,
- MAX_PRIORITY,相當於android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY,值為10。
- MIN_PRIORITY,相當於android.os.Process.THREAD_PRIORITY_LOWEST,值為0。
- NORM_PRIORITY,相當於android.os.Process.THREAD_PRIORITY_DEFAULT,值為5。
使用setPriority我們可以為某個執行緒設定優先順序,使用getPriority可以獲得某個執行緒的優先順序。
在Android系統中,不建議使用Java原生的API,因為Android提供的API劃分的級別更多,更適合在Android系統中進行設定細緻的優先順序。
注意
Android API的執行緒優先順序和Java原生API的優先順序是相對獨立的,比如使用 android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND) 後,使用Java原生API,Thread.getPriority()得到的值不會改變。如下面程式碼:
new Thread() { @Override public void run() { super.run(); Log.i(LOGTAG, "Java Thread Priority Before=" + Thread.currentThread().getPriority()); Process.setThreadPriority(Process.THREAD_PRIORITY_LOWEST); Log.i(LOGTAG, "Java Thread Priority=" + Thread.currentThread().getPriority()); } }.start();
上述程式碼的執行日誌為
I/MainActivity( 3679): Java Thread Priority Before=5 I/MainActivity( 3679): Java Thread Priority=5
由於上面的這一點缺陷,導致我們在分析ANR trace時需要注意,在下面的ANR日誌資訊中,prio=5中proi的值對應的Java原生API的執行緒優先順序。而nice=-6中的nice表示的Android API版本的執行緒優先順序。
"main" prio=5 tid=1 NATIVE | group="main" sCount=1 dsCount=0 obj=0x41690f18 self=0x4167e650 | sysTid=1765 nice=-6 sched=0/0 cgrp=apps handle=1074196888 | state=S schedstat=( 0 0 0 ) utm=5764 stm=3654 core=2 #00 pc 00022624 /system/lib/libc.so (__futex_syscall3+8) #01 pc 0000f054 /system/lib/libc.so (__pthread_cond_timedwait_relative+48) #02 pc 0000f0b4 /system/lib/libc.so (__pthread_cond_timedwait+64)
避免ANR
我在之前的文章說說Android中的ANR中提到使用WorkerThread處理耗時IO操作,同時將WorkerThread的優先順序降低,對於耗時IO操作,比如讀取資料庫,檔案等,我們可以設定該workerThread優先順序為THREAD_PRIORITY_BACKGROUND,以此降低與主執行緒競爭的能力。
相關文章
- 多執行緒------執行緒與程式/執行緒排程/建立執行緒執行緒
- Android程式框架:執行緒與執行緒池Android框架執行緒
- Android程式與執行緒Android執行緒
- android程式與執行緒詳解二:執行緒Android執行緒
- Android的程式與執行緒Android執行緒
- 程式執行緒排程方式執行緒
- 程序中的執行緒排程執行緒
- 執行緒、執行緒與程式、ULT與KLT執行緒
- android程式與執行緒詳解一:程式Android執行緒
- Android開發之旅:程式與執行緒Android執行緒
- 程式、執行緒、纖程之間的區別?執行緒
- Android中的多程式、多執行緒Android執行緒
- 掌握Android中的程式和執行緒Android執行緒
- android程式與執行緒詳解四:執行緒安全和程式間通訊Android執行緒
- 程式與執行緒執行緒
- 執行緒與程式執行緒
- Java執行緒中斷與終止執行緒執行Java執行緒
- android程式與執行緒詳解三:AsyncTaskAndroid執行緒
- Android的程式與執行緒使用總結Android執行緒
- Android《多執行緒-中》Android執行緒
- android程式和執行緒Android執行緒
- Android 程式和執行緒Android執行緒
- OpenMP 中的執行緒任務排程執行緒
- 程式設計思想之多執行緒與多程式(3):Java 中的多執行緒程式設計執行緒Java
- Java多執行緒1:程式與執行緒概述Java執行緒
- 程式與執行緒--原理執行緒
- 程式設計思想之多執行緒與多程式(4):C++ 中的多執行緒程式設計執行緒C++
- iOS 深入剖析多執行緒iOS執行緒
- 程式設計思想之多執行緒與多程式(2):執行緒優先順序與執行緒安全程式設計執行緒
- Android中的執行緒池Android執行緒
- Android中執行緒的使用Android執行緒
- Android的程式,執行緒模型Android執行緒模型
- 作業系統中的程式與執行緒作業系統執行緒
- Java執行緒的排程Java執行緒
- Android中UI執行緒與後臺執行緒互動設計的5種方法AndroidUI執行緒
- java中執行緒池的生命週期與執行緒中斷Java執行緒
- 執行緒與多執行緒執行緒
- 程式與執行緒區別執行緒