一、线程池的概念
线程池(Thread Pool)对于限制应用程序中同一时刻运行的线程数很有用。因为每启动一个新线程都会有相应的性能开销,每个线程都需要给栈分配一些内存等等。
我们可以把并发执行的任务传递给一个线程池,来替代为每个并发执行的任务都启动一个新的线程。只要池里有空闲的线程,任务就会分配给一个线程执行。在线程池的内部,任务被插入一个阻塞队列(Blocking Queue ),线程池里的线程会去取这个队列里的任务。当一个新任务插入队列时,一个空闲线程就会成功的从队列中取出任务并且执行它。
具体说来,线程池的出现正是着眼于减少线程池本身带来的开销。线程池采用预创建的技术,在应用程序启动之后,将立即创建一定数量的线程(N1),放入空闲队列中。这些线程都是处于阻塞(Suspended)状态,不消耗CPU,但占用较小的内存空间。当任务到来后,缓冲池选择一个空闲线程,把任务传入此线程中运行。当N1个线程都在处理任务后,缓冲池自动创建一定数量的新线程,用于处理更多的任务。在任务执行完毕后线程也不退出,而是继续保持在池中等待下一次的任务。当系统比较空闲时,大部分线程都一直处于暂停状态,线程池自动销毁一部分线程,回收系统资源。除此之外,线程池能够减少创建的线程个数。通常线程池所允许的并发线程是有上界的,如果同时需要并发的线程数超过上界,那么一部分线程将会等待。
Java 5 在 java.util.concurrent
包中自带了内置的线程池,这里我们只简述一下相关接口和类的使用。
二、常用类和接口
Executor接口:这个接口只包括一个execute方法,是具体Runnable线程任务的执行者
ExecutorService接口
public interface ExecutorService extends Executor
该接口是一个线程池管理者,继承了Executor类。
这个接口还具有执行Callable任务的能力,通过submit()执行,关于使用Callable和Future开启多线程的方法请参考文章 Java多线程:Callable、Future和FutureTask。该接口的实现类有ThreadPoolExecutor、ScheduledThreadPoolExecutor(具有调度功能)
AbstractExecutorService:ExecutorService执行方法的默认实现
ScheduledExecutorService:一个可定时调度任务的接口 ScheduledThreadPoolExecutor:ScheduledExecutorService的实现,一个可定时调度任务的线程池
ThreadPoolExecutor:线程池,可以通过调用Executors以下静态工厂方法来创建线程池并返回一个ExecutorService对象:
关于这个类的一个典型的构造方法如下:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
自定义线程池可以设定核心线程数、最大线程数、等待队列等信息。具体的参数设置不敢妄言,请查阅相关文档
ThreadPoolExecutor具有诸如启动一个线程、返回线程池配置、修改当前线程池配置等方法。
下面的例子,给了一个自定义线程池,并返回了线程池的信息
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
CallTask task = new CallTask();
for (int i = 0; i < 5; i++) {
threadPoolExecutor.submit(task);
}
threadPoolExecutor.setCorePoolSize(10); //修改线程池的核心线程数
System.out.println(threadPoolExecutor.getThreadFactory()); //返回线程工厂
System.out.println(threadPoolExecutor.getCorePoolSize()); //得到当前线程池的核心线程数
System.out.println(threadPoolExecutor.getPoolSize()); //得到池中的当前线程数
System.out.println(threadPoolExecutor.getMaximumPoolSize()); //得到允许的最大线程数
System.out.println(threadPoolExecutor.getQueue()); //返回执行程序使用的任务队列
}
输出结果
java.util.concurrent.Executors$DefaultThreadFactory@12a3a380
10
5
2147483647
[]
Executors类
提供了一系列静态工厂方法用于创建各种线程池,分别是:
newCachedThreadPool //创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool //创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool //创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor //创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
参考文献:java中Executor、ExecutorService、ThreadPoolExecutor介绍