线程池使用学习笔记
线程池的介绍
顾名思义线程池就是线程的池子,而这个池子它可以管理一个或多个线程,包括线程的创建以及使用,而身为Android开发至少对线程的使用还是多少了解的吧,毕竟Android建议我们将耗时操作放入到后台线程去进行以及4.0以后强制我们只有在后台线程中才能进行网络访问,这样就不会因为某些操作阻塞了UI线程中从而导致ANR(Android无响应)了。
线程池的使用
常见的线程池包括:
-
单线程的线程池
-
固定线程数的线程池
-
动态线程数的的线程池
-
自定义的线程池
接下来我就会从下面这些线程池入手分别介绍他们的使用和工作机制:
1.单线程的线程池
创建和使用单线程的线程池:
两个方法可以获取:ExecutorService newSingleThreadExecutor()
ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory )
// 创建单线程的线程池并执行
ExecutorService threadPool = Executors.newSingleThreadExecutor();
threadPool.execute(new SlowTask("task0"));
threadPool.execute(new SlowTask("task1"));
threadPool.execute(new SlowTask("task2"));
// 要做的任务
private static class SlowTask implements Runnable {
private String name;
public SlowTask(String name) {
this.name = name;
}
@Override
public void run() {
Log.i(TAG, "SlowTask " + name + " is running");
for (int i = 0; i < 10000; i++) {
for (int j = 0; j < 10000; j++) {
// 假装很耗时
}
}
}
@Override
public String toString() {
return "SlowTask:" + name;
}
}
单线程的线程池的工作机制:
单线程的线程池的工作机制.png
2.固定线程数的线程池:
两个方法可以获取:ExecutorService newFixedThreadPool(int threadCount)
ExecutorService newFixedThreadPool(int threadCount, ThreadFactory threadFactory )
// 创建一个固定5个线程数的线程池
ExecutorService threadPool = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
threadPool.execute(new SlowTask ("task" + i));
}
固定的线程池的工作机制:
固定线程数的线程池的工作机制.png3.动态线程数的线程池:
两个方法可以获取:ExecutorService newCachedThreadPool()
ExecutorService newCachedThreadPool(ThreadFactory threadFactory )
// 创建动态线程数的线程池通过自定义一个ThreadFactory
ExecutorService threadPool = Executors.newCachedThreadPool(5);
for (int i = 0; i < 10; i++) {
threadPool.execute(new SlowTask ("task" + i));
}
// 自定义的线程工厂
private static class MyThreadFactory implements ThreadFactory {
private static int count = 0;
@Override
public Thread newThread(Runnable r) {
Log.i(TAG, "第 " + (count++) + " 个线程创建");
return new Thread(r);
}
}
动态线程数的线程池的工作机制:
动态线程数的线程池的工作机制.png4.自定义的的线程池:
想要使用自定义线程池的时候我们需要使用到一个类——ThreadPoolExecutor,其实我们在创建上面那三个线程池的时候都是Executors帮我们去通过创建ThreadPoolExecutor来实现的,如图:
Executors类的部分源码.png
这个时候我们来看看ThreadPoolExecutor类的构造函数,当我们看构造函数我们就知道传哪些参数就可以帮我实现相同的效果或者他上面三个完全不同的效果,我们来看一个最长的构造函数:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory ,
RejectedExecutionHandler handler)
那我就从上到下一个个来说明他们的含义:
1.corePoolSize:核心线程数
2.maximumPoolSize:核心线程数
3.keepAliveTime:空闲线程的存活时间
4.unit:空闲线程存活时间的单位
5.workQueue:任务等待队列
6.threadFactory:线程工厂
7.handler:处理器, 当线程数已经满了, 也已经没有空闲线程了, 并且且任务等待队列队列也满了, 接受不了任务了的时候就会把该任务交给handler进行处理。
在了解了构造器这些参数之后就可以很方便我们自定义线程池了(当然还有多个构造函数, 所以不一定使用这一个, 这是参数最多的构造函数):
// 创建了一个核心线程数为2,最大线程数为10的自定义线程
ExecutorService threadPool = new ThreadPoolExecutor(2, 10,
60L, TimeUnit.SECONDS,
new LinkedBlockingDeque<Runnable>(10),
new MyThreadFactory(),
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
Log.i(TAG, "被拒任务名称是: " + r.toString());
}
});
for (int i = 0; i < 20; i++) {
try {
threadPool.execute(new SlowTask("Task" + i));
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
自定义线程池的工作机制:
自定义线程池的工作机制.png
5.关闭线程池
调用shutdown()或者调用shutdownNow()就可以了,可以通过isShutdown()判断是否关闭.
shutdown()和shutdownNow()的区别如下图:
shutdown()和shutdownNow()的区别.png
6.各个线程池的使用场景
各个线程池的使用场景(N为CPU数).png线程池的实践
我使用上述各类线程池写了一个图片预览器, App截图如下(手机截图有点大):
选择界面.png
下面获取到的妹子图片来自Gank.io, 如果是单线程的线程池图片会一张一张显示出来, 而固定线程我写了3个,所以会三个三个显示出来,而动态线程数的线程池和自定义线程池都是会一口气显示很多
图片展示界面.png
项目我已上传Github, 地址为https://github.com/GzwJaaaelu/ThreadPoolExecutorDemo
Demo可能还有待完善的地方,请大家指出。
我希望可以站在初学者&自学者的角度把Android中的知识点很清楚的介绍给大家,希望大家喜欢。 如果有错误希望指出来,有问题或者没看懂,都可以来问我的