前一篇文章对ThreadPoolExecutor的配置进行了详细的阐述Java线程池详解(一),本节我们将分析Java中最常见的四类具有不同功能的线程池,它们都是通过直接或间接配置ThreadPoolExecutor来实现自己的特性,这四类线程池分别是(通过Executors工具类来创建):
(1)newCachedThreadPool:线程数量不定的线程池,只有非核心线程,并且其最大线程数为Integer.MAX_VALUE,当线程池中的线程都处于活动状态时,线程池将创建新线程来执行任务,否则将利用空闲线程执行任务。其线程池具有超时策略,超过60s的闲置线程将被回收,适合执行大量的耗时较少的任务。
(2)newFixedThreadPool:线程数固定的线程池,其只有核心线程并且不会被回收,所以当所有线程都处于活动状态时,新任务都将处于等待状态,直到有线程空闲下来。
(3)newScheduledThreadPool 创建核心线程数固定,非核心线程数为Integer.MAX_VALUE的线程池,当非核心线程闲置时会被立即回收,主要用于执行定时任务和固定周期的重复任务。
(4)newSingleThreadExecutor 创建只有一个核心线程的线程池,它只会用唯一的工作线程来执行任务,以确保所有的任务都在同一线程中按顺序执行,无需处理线程同步问题。
以上只是对四类线程池总的概述,接下来我们将单独详细分析,每种线程池我们都给出其创建源码和示例。
//创建线程池
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
//创建ThreadPoolExecutor对象,核心线程数0,线程最大数Integer.MAX_VALUE,超时时长60s
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue(),
threadFactory);
}
//测试代码
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 20; i++) {
final int index = i;
cachedThreadPool.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
20个数会在一瞬间全部打印出来。
//创建线程池
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
//创建ThreadPoolExecutor对象,此时只有核心线程,并且没有闲置超时策略
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(),
threadFactory);
}
//测试代码
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
for (int i = 0; i < 20; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
此时核心线程只有4个,每次只能输出4个数,然后等待3秒后将输出下一波四个数。
//创建线程池
public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory) {
//创建ScheduledThreadPoolExecutor对象
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory) {
//调用父类的构造器,核心线程数固定,非核心线程数Integer.MAX_VALUE,非核心线程闲置会立即回收
super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
new DelayedWorkQueue(), threadFactory);
}
由代码看见,其最终还是通过创建ThreadPoolExecutor对象来创建线程池。
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
public void run() {
System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);
表示延迟3秒后执行一次;
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println("delay 1 seconds, and excute every 3 seconds");
}
}, 1, 3, TimeUnit.SECONDS);
表示延迟1秒后每3秒执行一次;
//创建线程池
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
//创建只有一个核心线程,没有非核心线程的线程池,所有任务按序执行
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(),
threadFactory));
}
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 20; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
此时核心线程数只有一个,没有非核心线程数,所有任务按序执行,每隔3s打印一次数据。
好啦,四种常用线程池我们就分析到这里啦。