在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
}
});