在Android項目中,我們創建的Service、Activity以及Broadcast均是一個主線程處理,這裏我們可以理解爲UI線程.但是在操作一些耗時操作時,比如I/O讀寫的大文件讀寫,數據庫操作以及網絡下載需要很長時間,爲了不阻塞用戶界面,出現ANR的響應提示窗口,這個時候我們可以考慮使用Thread線程來解決.先來簡單瞭解一下線程的調度原理及模型:
線程調度原理:
任一時刻,只有一個線程佔用CPU,處於運行狀態
多線程併發:
輪流獲取CPU使用權
線程調度模型:
分時調度模型:輪流獲取、均分CPU時間
搶佔式調度模型:優先級好的獲取,JVM採用這種方式。
nice值、cgroup
nice值:
1)Process中定義
2)值越小,優先級越高
3)默認是THREAD_PRIORITY_DEFAULT,0
cgroup:
1) 更嚴格的羣組調度策略。
2) 保證前臺線程可以獲取到更多的CPU
注意點:
線程過多會導致CPU頻繁切換,降低線程運行效率
正確認識任務重要性決定哪種優先級。 (工作量越大優先級越低)
優先級具有繼承性
常見使用方式:
不正確使用方式:
new Thread(new Runnable() {
@Override
public void run() {
//執行業務
}
}).start();
缺點:
a. 每次new Thread新建對象,性能相對較差;
b. 線程缺乏統一管理,可能無限制新建線程,相互之間競爭,及可能佔用過多系統資源導致anr死機或oom;
相比new Thread,Java提供的四種線程池的好處在於:
1. 重用存在的線程,減少對象創建、消亡的開銷,性能佳。
2. 可有效控制最大併發線程數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞。
3. 提供定時執行、定期執行、單線程、併發數控制等功能。
四種線程池的創建方式:
newCacheThreadPool一個無限大並可以緩存的線程池。在之前創建新線程的時刻首先複用已經創建過的空閒線程。
ExecutorService cacheThreadPool = Executors.newCachedThreadPool();
newFixedThreadPool 可以控制最大併發數的線程池。超過最大併發數的線程進入等待隊列
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
newScheduledThreadPool 一個可以定時執行的線程池。
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
}
},1, TimeUnit.SECONDS);
newSingleThreadExecutor 單線程化線程池。支持FIFO、LIFO的優先級執行。
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
以上都是在說創建線程池並且將業務代碼放到線程池中,如果應用中很多地方都需要多線程,如果我們都去new 線程池的話,就會造成線程池代碼冗餘,代碼閱讀性較差,這時我們需要一個線程池管理工具,如下:
public class AppExecutors {
private static final String TAG = "AppExecutors";
/**磁盤IO線程池**/
private final ExecutorService diskIO;
/**網絡IO線程池**/
private final ExecutorService networkIO;
/**UI線程**/
private final Executor mainThread;
/**定時任務線程池**/
private final ScheduledExecutorService scheduledExecutor;
public static AppExecutors getInstance() {
if (appExecutors == null) {
synchronized (AppExecutors.class) {
if (appExecutors == null) {
appExecutors = new AppExecutors();
}
}
}
return appExecutors;
}
public AppExecutors(ExecutorService diskIO, ExecutorService networkIO, Executor mainThread, ScheduledExecutorService scheduledExecutor) {
this.diskIO = diskIO;
this.networkIO = networkIO;
this.mainThread = mainThread;
this.scheduledExecutor = scheduledExecutor;
}
public AppExecutors() {
this(diskIoExecutor(), networkExecutor(), new MainThreadExecutor(), scheduledThreadPoolExecutor());
}
/**
* 定時(延時)任務線程池
*
* 替代Timer,執行定時任務,延時任務
*/
public ScheduledExecutorService scheduledExecutor() {
return scheduledExecutor;
}
/**
* 磁盤IO線程池(單線程)
*
* 和磁盤操作有關的進行使用此線程(如讀寫數據庫,讀寫文件)
* 禁止延遲,避免等待
* 此線程不用考慮同步問題
*/
public ExecutorService diskIO() {
return diskIO;
}
/**
* 網絡IO線程池
*
* 網絡請求,異步任務等適用此線程
* 不建議在這個線程 sleep 或者 wait
*/
public ExecutorService networkIO() {
return networkIO;
}
/**
* UI線程
*
* Android 的MainThread
* UI線程不能做的事情這個都不能做
*/
public Executor mainThread() {
return mainThread;
}
private static ScheduledExecutorService scheduledThreadPoolExecutor() {
return new ScheduledThreadPoolExecutor(16, r -> new Thread(r, "scheduled_executor"), (r, executor) -> Log.e(TAG, "rejectedExecution: scheduled executor queue overflow"));
}
private static ExecutorService diskIoExecutor() {
return new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1024), r -> new Thread(r, "disk_executor"), (r, executor) -> Log.e(TAG, "rejectedExecution: disk io executor queue overflow"));
}
private static ExecutorService networkExecutor() {
return new ThreadPoolExecutor(3, 6, 1000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(6), r -> new Thread(r, "network_executor"), (r, executor) -> Log.e(TAG, "rejectedExecution: network executor queue overflow"));
}
private static class MainThreadExecutor implements Executor {
private final Handler mainThreadHandler = new Handler(Looper.getMainLooper());
@Override
public void execute(@NonNull Runnable command) {
mainThreadHandler.post(command);
}
}
}
用法:
UI線程:
AppExecutors.getInstance().mainThread().execute(new Runnable() {
@Override
public void run() {
//to do
}
});
磁盤IO線程池:
AppExecutors.getInstance().diskIO().execute(new Runnable() {
@Override
public void run() {
//to do
}
});
網絡IO線程池:
AppExecutors.getInstance().networkIO().execute(new Runnable() {
@Override
public void run() {
//to do
}
});