线程池
Java线程池概念
new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), Runtime.getRuntime().availableProcessors() * 2, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(100));
顾名思义,管理线程的池子,相比于手工创建、运行线程,使用线程池,有如下优点
- 降低线程创建和销毁线程造成的开销
- 提高响应速度。任务到达时,相对于手工创建一个线程,直接从线程池中拿线程,速度肯定快很多
- 提高线程可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统稳定性,使用线程池可以进行同意分配、调优和监控
Java线程池创建
无论是创建何种类型线程池(FixedThreadPool、CachedThreadPool...),均会调用ThreadPoolExecutor构造函数,下面详细解读各个参数的作用
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
- corePoolSize:核心线程最大数量,通俗点来讲就是,线程池中常驻线程的最大数量
- maximumPoolSize:线程池中运行最大线程数(包括核心线程和非核心线程)
- keepAliveTime:线程池中空闲线程(仅适用于非核心线程)所能存活的最长时间
- unit:存活时间单位,与keepAliveTime搭配使用
- workQueue:存放任务的阻塞队列
- handler:线程池饱和策略
线程池执行流程
当提交一个新任务,线程池的处理流程如下:
- 判断线程池中核心线程数是否已达阈值
corePoolSize,若否,则创建一个新核心线程执行任务 - 若核心线程数已达阈值
corePoolSize,判断阻塞队列workQueue是否已满,若未满,则将新任务添加进阻塞队列 - 若满,再判断,线程池中线程数是否达到阈值
maximumPoolSize,若否,则新建一个非核心线程执行任务。若达到阈值,则执行线程池饱和策略。
线程池饱和策略分为一下几种:
- AbortPolicy:直接抛出一个异常,默认策略
- DiscardPolicy: 直接丢弃任务
- DiscardOldestPolicy:抛弃下一个将要被执行的任务(最旧任务)
- CallerRunsPolicy:主线程中执行任务
从流程角度,更形象的图:

从结构角度,更形象的图:

几种典型的工作队列
- ArrayBlockingQueue:使用数组实现的有界阻塞队列,特性先进先出
- LinkedBlockingQueue:使用链表实现的阻塞队列,特性先进先出,可以设置其容量,默认为
Interger.MAX_VALUE,特性先进先出 - PriorityBlockingQueue:使用平衡二叉树堆,实现的具有优先级的无界阻塞队列
- DelayQueue:无界阻塞延迟队列,队列中每个元素均有过期时间,当从队列获取元素时,只有过期元素才会出队列。队列头元素是最块要过期的元素。
- SynchronousQueue:一个不存储元素的阻塞队列,每个插入操作,必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态
常用的几种线程池
newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
这种类型的线程池特点是:
- 工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程。
- 如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(默认为1分钟),则该工作线程将自动终止。终止后,如果你又提交了新的任务,则线程池重新创建一个工作线程。
- 在使用CachedThreadPool时,一定要注意控制任务的数量,否则,由于大量线程同时运行,很有会造成系统瘫痪。
示例代码如下:
1 package test;
2 import java.util.concurrent.ExecutorService;
3 import java.util.concurrent.Executors;
4 public class ThreadPoolExecutorTest {
5 public static void main(String[] args) {
6 ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
7 for (int i = 0; i < 10; i++) {
8 final int index = i;
9 try {
10 Thread.sleep(index * 1000);
11 } catch (InterruptedException e) {
12 e.printStackTrace();
13 }
14 cachedThreadPool.execute(new Runnable() {
15 public void run() {
16 System.out.println(index);
17 }
18 });
19 }
20 }
21 }
newFixedThreadPool
创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。
FixedThreadPool是一个典型且优秀的线程池,它具有线程池提高程序效率和节省创建线程时所耗的开销的优点。但是,在线程池空闲时,即线程池中没有可运行任务时,它不会释放工作线程,还会占用一定的系统资源。
示例代码如下:
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。
定长线程池的大小最好根据系统资源进行设置如Runtime.getRuntime().availableProcessors()。
newSingleThreadExecutor
创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果这个线程异常结束,会有另一个取代它,保证顺序执行。单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。
示例代码如下:
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
newScheduleThreadPool
创建一个定长的线程池,而且支持定时的以及周期性的任务执行,支持定时及周期性任务执行。
延迟3秒执行,延迟执行示例代码如下:
package test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
public void run() {
System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);
}
}
表示延迟1秒后每3秒执行一次,定期执行示例代码如下:
package test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
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);
}
}


浙公网安备 33010602011771号