线程池简介
线程池(英语:thread pool):一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度
线程池的优势
线程池做的工作只要是控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。
四大线程池
Java通过Executors提供四种线程池,分别为
- newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
- newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
- newScheduledThreadPool 创建一个可定期或者延时执行任务的定长线程池,支持定时及周期性任务执行。
- newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
案例演示
一池一线程
案例:银行只开放了一个窗口,有10个用户在办理业务
public static void main(String[] args) {
//一池一线程
//一个窗口
ExecutorService threadPool = Executors.newSingleThreadExecutor();
//10个顾客请求
try {
for (int i = 1; i <=10; i++) {
//执行
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+" 办理业务");
});
}
}catch (Exception e) {
e.printStackTrace();
}finally {
//关闭
threadPool.shutdown();
}
}
一个线程处理了10个业务办理
一池N线程
案例:银行开放了5一个窗口,有10个用户在办理业务
public static void main(String[] args) {
//一池五线程
//5个窗口
ExecutorService threadPool = Executors.newFixedThreadPool(5);
//10个顾客请求
try {
for (int i = 1; i <=10; i++) {
//执行
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+" 办理业务");
});
}
}catch (Exception e) {
e.printStackTrace();
}finally {
//关闭
threadPool.shutdown();
}
}
5个线程处理10个业务办理
一池可扩容线程(遇强则强)
案例:只有10个用户在银行办理业务的之后,银行只需要开5个窗口处理;当有20个用户办理业务的时候,银行增加了窗口数量,开了8个窗口
public static void main(String[] args) {
//一池可扩容线程
ExecutorService threadPool = Executors.newCachedThreadPool();
//10个顾客请求
try {
for (int i = 1; i <=10; i++) {
//执行
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+" 办理业务");
});
}
}catch (Exception e) {
e.printStackTrace();
}finally {
//关闭
threadPool.shutdown();
}
}
当i<= 5时,创建了5个线程处理【具体数量和电脑配置有关系】
当i<=30,可以看到创建13个线程来处理【具体数量和电脑配置有关系】
执行周期性任务
/**
* 创建一个定长线程池,支持定时及周期性任务执行。延迟执行
*/
public static void sceduleThreadPool() {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
Runnable r1 = () -> out.println("线程名称:" + Thread.currentThread().getName() + ",执行:3秒后执行");
scheduledThreadPool.schedule(r1, 3, TimeUnit.SECONDS);
Runnable r2 = () -> out.println("线程名称:" + Thread.currentThread().getName() + ",执行:延迟2秒后每3秒执行一次");
scheduledThreadPool.scheduleAtFixedRate(r2, 2, 3, TimeUnit.SECONDS);
Runnable r3 = () -> out.println("线程名称:" + Thread.currentThread().getName() + ",执行:普通任务");
for (int i = 0; i < 5; i++) {
scheduledThreadPool.execute(r3);
}
}
打印:
----output------
线程名称:pool-1-thread-1,执行:普通任务
线程名称:pool-1-thread-5,执行:普通任务
线程名称:pool-1-thread-4,执行:普通任务
线程名称:pool-1-thread-3,执行:普通任务
线程名称:pool-1-thread-2,执行:普通任务
线程名称:pool-1-thread-1,执行:延迟2秒后每3秒执行一次
线程名称:pool-1-thread-5,执行:3秒后执行
线程名称:pool-1-thread-4,执行:延迟2秒后每3秒执行一次
线程名称:pool-1-thread-4,执行:延迟2秒后每3秒执行一次
线程名称:pool-1-thread-4,执行:延迟2秒后每3秒执行一次
线程名称:pool-1-thread-4,执行:延迟2秒后每3秒执行一次
线程池参数说明
四种线程池本质都是创建ThreadPoolExecutor类,ThreadPoolExecutor构造参数如下
int corePoolSize, 线程池的核心线程数
int maximumPoolSize ,最大线程大小
long keepAliveTime, 超过corePoolSize的线程多久不活动被销毁时间
TimeUnit unit,时间单位
BlockingQueue<Runnable> workQueue 任务队列
ThreadFactory threadFactory 线程池工厂
RejectedExecutionHandler handler 拒绝策略