目录
1、线程池简介
2、线程池的好处
3、线程池执行任务的规则
4、线程池的分类
1)FixedThreadPool类型
2)CachedThreadPool类型
3)ScheduleThreadPool类型
4)SingleThreadExecutor类型
线程池是在java开发中很重要的一个概念,Android中的线程池和和java是保持一致的,并无什么区别。线程池是一个抽象的概念,在java中是一个接口类,用Executor表示, 具体实现类为ThreadPoolExecutor,它们位于java.util.concurrent包下面,这个接口类很短,而且接口声明就只有一个,并且注释中说明了一些情况怎么使用,
package java.util.concurrent;
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}
上面省略了注释,可以看注释,很管用,上面有模版,教我们怎么创建一个自己线程池,其中有段是这么说的:许多线程池的实现类对将要执行的任务的方式和时间做了限制,下面展示了串型线程池在执行任务的时候,从一个任务到下一个任务的过程。
下面代码来至注释中的举例,说明了一个从任务如何进入到下一个任务的串行执行过程:
package demo.xx.patten.xx;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.concurrent.Executor;
public class SerialExecutor implements Executor {
final Queue tasks = new ArrayDeque<>();
final Executor executor;
Runnable active;
public SerialExecutor(Executor executor) {
this.executor = executor;
}
public synchronized void execute(final Runnable r) {
tasks.add(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (active == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((active = tasks.poll()) != null) {
executor.execute(active);
}
}
}
上面的SerialExecutor管理了一个Runnable对象的任务列队tasks和一个从构造函数中传入的线程池,每次调用SerialExecutor的execute方法的时候都会传入一个Runnable对象,然后将这个runnbale的执行方法run方法包装进一个新建的Runnable对象中,然后将这个新建的Runnbale对象插入tasks队列中。紧接着由于初始化的时候active是null,于是会首先执行scheduleNext()方法,这个时候通过tasks.poll()方法将插入的任务,也就是Runnable对象取出来交给构造函数中传入的Executor对象实例来执行,注意上面try的finally块中在r.run()被执行后都会被调用,这就保证了从一个任务到下一个任务的传递,因为active在第一执行scheduleNext后会被负值,之后就不等于null了,那么判断语句就不会被执行了。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory) {
}
从前面的介绍我们了解到,要直接创建一个线程池,需要传入很多个参数,这在实际使用中,就会显得比较麻烦,所以在Executors这个线程池工具类中,给我们提供了更加简单的创建线程池的API, 主要有四种类型,注意仅仅是类型,并不是存在的java类
通过Executors.newFixedThreadPool(int nThreads)创建
创建一个固定线程数量的线程池,线程池中的所有线程都是核心线程,当线程空闲时不会被回收,也不会超时,除非线程池被关闭,当线程池中线程都处于活动状态的时候,新进任务会处于等待状态,直到有线程空出来去处理,处于等待状态的任务会在任务列队中排队等候,这个列队的容量没有大小限制,由于线程不会被回收,这样便能够快速的响应外界请求。
通过Executors.newCachedThreadPool()创建
这是一个线程池的线程的数量是不定的,所有线程都是非核心线程,最大线程数量为Integer.MAX_VALUE,当线程池中线程都处于活动状态的时候,线程池会创建新的线程池来处理新进任务,否则就会利用空闲线程来处理新进任务,线程池中的线程都有60s的超时机制,超过时间的线程会被回收。
使用场景:大量的耗时较少的任务
通过Executors.newScheduleThreadPool(int corePoolSize)创建。
这种线程池的核心线程数是固定的,非核心线程数量没有限制,并且非核心线程执行完任务会被立刻回收,非核心线程没有闲置的状态。
使用场景:定时任务和固定周期的重复任务
通过Executors.newSingleThreadExecutor()创建
SingleThreadExecutor内部只有唯一一个核心线程用来执行任务,其确保了所有的任务都在一个线程中执行,SingleThreadExecutor存在的意义在于统一所有的外界任务到一个线程中去执行,这样这些任务就不需要处理线程同步的问题。