1. 什么是线程池?
线程池其实就是将多个线程对象放到一个容器当中。
2. 为什么使用线程池?
可以重用线程,减少创建和销毁线程带来的消耗。
3. 如何使用线程池?
要想知道如何使用线程池,就要先知道线程池的种类有多少种?线程池大概有以下几种:
- ThreadPoolExecutor
- FixedThreadPool
- CahcedThreadPool
- SingleThreadExecutor
- ScheduledThreadPool
以下介绍这几种线程池的用法:
3.1 ThreadPoolExecutor
ThreadPoolExecutor 是线程池真正的实现方法,以下是 ThreadPoolExecutor 的构造方法:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
它需要传入一系列参数来配置线程池,下面介绍每个参数的意义。
参数 | 意义 |
---|---|
corePoolSize | 线程池的核心线程数 |
maximumPoolSize | 线程池容纳最大的线程数 |
keepAliveTime | 非核心线程闲置时的超时时长 |
unit | keepAliveTime 参数的时间单位 |
workQueue | 线程池中的任务队列 |
threadFactory | 线程工厂,为线程池提供创建新线程的功能 |
3.2 FixedThreadPool
一种固定线程数量的线程池。
可以通过 Executors 的 newFixedThreadPool() 方法创建:
ExecutorService pool = Executors.newFixedThreadPool(4);
newFixedThreadPool() 具体实现:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
可以看出 newFixedThreadPool() 是通过创建 ThreadPoolExecutor 来创建线程池的。
并且因为 corePoolSize 和 maximumPoolSize 是一样的,所以这种线程池只有核心线程,任务超出线程数后,会在队列中等待。
具体使用如下:
ExecutorService pool = Executors.newFixedThreadPool(4);
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("haha");
}
};
pool.execute(task);
3.3 CahcedThreadPool
一种线程数量不定的线程池。
可以通过 Executors 的 newCachedThreadPool() 方法创建:
ExecutorService pool = Executors.newCachedThreadPool();
newCachedThreadPool() 具体实现:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
可以看到 corePoolSize 为 0,maximumPoolSize 为 Integer.MAX_VALUE,证明这种线程池没有核心线程,但是有多个非核心线程。
这种线程池的特点就是,当有任务提交时,如果有空闲线程则复用空闲线程,没有的话就新建线程处理。
空闲线程如果超过 60 秒就会被回收。
具体使用如下:
ExecutorService pool = Executors.newCachedThreadPool();
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("haha");
}
};
pool.execute(task);
3.4 SingleThreadExecutor
一种只有一个工作线程的线程池。
可以通过 Executors 的 newSingleThreadExecutor() 方法创建:
ExecutorService pool = Executors.newSingleThreadExecutor();
newSingleThreadExecutor() 具体实现:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
从源码可以看出,这种线程池只有一个核心线程,并且总线程数为 1。
具体使用如下:
ExecutorService pool = Executors.newSingleThreadExecutor();
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("haha");
}
};
pool.execute(task);
3.5 ScheduledThreadPool
一种核心线程数量固定,非核心线程数不固定的线程池。
可以通过 Executors 的 newScheduledThreadPool() 方法创建:
ExecutorService pool = Executors.newScheduledThreadPool(4);
newScheduledThreadPool() 具体实现:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
// DEFAULT_KEEPALIVE_MILLIS = 10L
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
// 进去 super 的代码
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
从源码可以看出这种线程池的核心线程是固定的,非核心线程数没有限制,但是非核心线程出现空闲后,10 毫秒就会被回收。
具体使用:
ExecutorService pool = Executors.newFixedThreadPool(4);
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("haha");
}
};
// 1 秒后执行任务
pool.schedule(task, 1, TimeUnit.SECONDS);
// 延迟 10 毫秒后,每隔 2000 毫秒执行一次任务
pool.scheduleAtFixedRate(task, 10,2000, TimeUnit.MICROSECONDS);