Github地址:新聞?lì)怉pp (MVP + RxJava + Retrofit+Dagger+ARouter)
線程調(diào)度原理
- 任意時(shí)刻,只有一個(gè)線程調(diào)用CPU,處于運(yùn)行時(shí)狀態(tài)
- 多線程并發(fā):輪流獲取CPU使用權(quán)
- JVM負(fù)責(zé)線程調(diào)度:按照特定機(jī)制分配CPU使用權(quán)
線程調(diào)度模型
- 分時(shí)調(diào)度模型:輪流獲取,均分cpu時(shí)間
- (java虛擬機(jī)采用)搶占式調(diào)度模型:優(yōu)先級(jí)高的獲取
Android線程調(diào)度
nice值
- process中定義的
- 值越小,優(yōu)先級(jí)越高
-
默認(rèn)是THREAD_PRIORITY_DEFAULT =0
優(yōu)先級(jí).png
cgroup
- 更嚴(yán)格的群組(前臺(tái)和后臺(tái))調(diào)度策略
- 保證前臺(tái)線程可以獲取到更多的cpu
哪些線程會(huì)移動(dòng)到后臺(tái)group:1.手動(dòng)設(shè)置優(yōu)先級(jí)低的 2.不在前臺(tái)運(yùn)行的應(yīng)用程序的線程
1.線程過多會(huì)導(dǎo)致CPU切換頻繁,降低線程運(yùn)行效率
2.正確認(rèn)識(shí)任務(wù)重要性j決定哪種優(yōu)先級(jí)
3.優(yōu)先級(jí)具有繼承性
android異步方式匯總
Thread
- 最簡(jiǎn)單,最常見的異步方式(最不推薦)
- 不易復(fù)用,頻繁創(chuàng)建及銷毀開銷大
- 復(fù)雜場(chǎng)景不易使用
HandlerThread
- 自帶消息循環(huán)的線程
- 串行執(zhí)行
- 長(zhǎng)時(shí)間運(yùn)行,不斷從隊(duì)列中獲取任務(wù)
IntentService
- 繼承自Service在內(nèi)部創(chuàng)建HandlerThread
- 異步,不占用主線程
- 優(yōu)先級(jí)較高,不易輕易被kill
AsyncTask
- android提供的工具類
- 無需自己處理線程
- 需注意版本不一致問題
線程池
- java提供的線程池
- 易復(fù)用減少頻繁創(chuàng)建,銷毀的時(shí)間
- 功能強(qiáng)大:定時(shí),任務(wù)隊(duì)列,并發(fā)數(shù)控制等
Rxjava
- 由強(qiáng)大的Scheduler集合提供
- 不同類型的區(qū)分:IO,Computation
Android線程優(yōu)化實(shí)戰(zhàn)
異步使用規(guī)則
- 嚴(yán)禁直接new Thread
- 提供基礎(chǔ)線程池供各個(gè)業(yè)務(wù)線使用
避免各個(gè)業(yè)務(wù)線各自維護(hù)一套線程池,導(dǎo)致線程數(shù)過多 - 根據(jù)任務(wù)類型選擇合適的異步方式
- 創(chuàng)建線程必須命名
方便定位線程歸屬
運(yùn)行期Thread.currentThread.setName修改名字 - 關(guān)鍵異步任務(wù)監(jiān)控
異步不等于不耗時(shí)
AOP的方式實(shí)現(xiàn)監(jiān)控 - 重視優(yōu)先級(jí)設(shè)置
Process.setThredPriority()
可以設(shè)置多次
實(shí)戰(zhàn)
- 第一種方式:Executors,會(huì)提示:手動(dòng)創(chuàng)建線程池,效果會(huì)更好哦
public class ThreadPoolUtils {
/**
* 會(huì)提示:手動(dòng)創(chuàng)建線程池,效果會(huì)更好哦
*/
private static ExecutorService sService = Executors.newFixedThreadPool(5, new ThreadFactory() {
@Override
public Thread newThread(@NonNull Runnable runnable) {
Thread thread = new Thread();
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
thread.setName("ThreadPoolUtils's ExecutorService");
return thread;
}
});
public static ExecutorService getService() {
return sService;
}
}
使用
ThreadPoolUtils.getService().execute(new Runnable() {
@Override
public void run() {
//提高優(yōu)先級(jí)
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
String oldName = Thread.currentThread().getName();
//方便查看哪個(gè)線程報(bào)錯(cuò)
Thread.currentThread().setName("MainActivity Thread Name");
Thread.currentThread().setName(oldName);
}
});
- 第二種方式:手動(dòng)創(chuàng)建線程池
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return new Thread(r, "ThreadPoolUtils's ThreadFactory" + mCount.getAndIncrement());
}
};
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
private static final ThreadPoolExecutor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
public static ThreadPoolExecutor getThreadPoolExecutor() {
return THREAD_POOL_EXECUTOR;
}
鎖定線程創(chuàng)建者
鎖定線程創(chuàng)建背景
- 項(xiàng)目變大之后收斂線程
- 項(xiàng)目源碼,三方庫,aar中都有線程的創(chuàng)建
- 避免惡化的一種監(jiān)控預(yù)防手段
方案分析
- 創(chuàng)建線程的位置獲取堆棧
- 所有的異步方式都會(huì)走到new Thread
- 比較適合hook手段
找hook點(diǎn):構(gòu)造函數(shù)或者特定方法
Thread的構(gòu)造函數(shù)
優(yōu)雅的方案:ARTHook
- 掛鉤,將額外的代碼鉤住原有的方法,修改執(zhí)行邏輯
- 框架:Epic(不能帶到線上環(huán)境)
DexposedBridge.hookAllConstructors(Thread.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Thread thread = (Thread) param.thisObject;
LogUtils.i(thread.getName() + " stack " + Log.getStackTraceString(new Throwable()));
}
});
線程收斂方案
- 直接依賴線程庫
- 缺點(diǎn):線程庫更新可能會(huì)導(dǎo)致基礎(chǔ)庫更新
- 基礎(chǔ)庫內(nèi)部暴露API:setExecutor
- 初始化的時(shí)候注入統(tǒng)一的線程庫
- 代碼。工具類里面添加代碼(UIUtils)
private static ExecutorService sExecutorService;
public static void setExecutorService(ExecutorService executorService) {
sExecutorService = executorService;
}
public static void exectur(Runnable runnable) {
//如果外部庫不為空,則使用外部,否則使用自己的
if (sExecutorService != null) {
sExecutorService.execute(runnable);
} else {
ThreadPoolUtils.getService().execute(runnable);
}
}
注意:1.要區(qū)分任務(wù)類型:IO還是CPU密集型,IO就是上面優(yōu)化實(shí)戰(zhàn)的第一種方式Executors,CPU就是第二種方式手動(dòng)創(chuàng)建
2.IO密集型任務(wù)不消耗CPU,核心池可以很大
3.CPU密集型任務(wù):核心池大小h和CPU核心數(shù)有關(guān)
