在编程中经常会使用线程来进行异步处理,但是每个线程的创建和销毁都有一定的系统资源消耗。如果每次执行一个任务都要开一个新线程去执行,则这些现成的创建和销毁将消耗大量的系统资源,所以利用线程池来来提高系统资源的利用效率,并简化线程的管理。
在Java1.5中提供了Executor框架来用于把任务的提交和执行解耦,通过execute和submit方法将Runnable或Callable任务提交给Executor框架来执行。在Executor框架中可以通过ThreadPoolExecutor来创建一个线程池,ThreadPoolExecutor的其中一个构造函数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
.....
}
这些参数的作用如下:
线程池的饱和策略除了默认的AbortPolicy以外还包括三种策略:
(1).CallerRunsPolicy:用调用者所处的线程来处理任务。这样会影响调用者线程的性能
(2).DiscardPolicy:丢弃不能执行的任务,不做任何处理。
(3).DiscardOldestPolicy:丢弃队列最近的任务,并执行当前任务。
当有一个新的任务提交到线程池时,线程池的处理过程如下图所示:
具体的处理流程分为如下几个过程:
在用到线程池的时候,我们都是使用Executors提供的通用线程池创建方法,去创建不同配置的线程池。目前Executors框架提供了5种常用的线程池。
它是一种用来处理大量短时间任务的线程池。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}
复用指定数目(nThreads)的线程。它的定义如下:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
newFixedThreadPool线程池的特点:
SingleThreadExecutor是只包含一个工作线程的线程池,它的定义如下:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()));
}
它的核心线程数和线程总数都为1,意味着SingleThreadExecutor只有一个核心线程。当有任务提交时如果线程池还没有创建核心线程则先创建核心线程后开始处理任务,如果核心线程已经创建,则将任务放置在阻塞队列等候处理。因此SingleThreadExecutor线程池能保证所有的任务在一个线程中串行执行。
ScheduledThreadPool是一种能够定时和周期性执行的线程池,它的定义如下:
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
ScheduledThreadPoolExecutor类继承自ThreadPoolExecutor,最终调用的还是ThreadPoolExecutor的构造函数。当调用scheduleAtFixedRate()或者scheduleWithFixedDelay()方法的时候,会将任务添加到DelayedWorkQueue队列中。DelayedWorkQueue队列会将任务进行排序,先要执行的任务放置在前边。