11_线程池
Posted root_zhb
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了11_线程池相关的知识,希望对你有一定的参考价值。
线程池
1、线程池概述
由于线程的创建和回收这两个过程是非常消耗性能的,
利用池化思想,事先创建好一些线程放入线程池中,使用完之后线程池再回收线程,达到减小资源开销的目的。
主要特点:
- 降低资源消耗: 通过重复利用已创建的线程降低线程创建和销毁造成的销耗。
- 提高响应速度: 当任务到达时,任务可以不需要等待线程创建就能立即执行。
- 提高线程的可管理性: 线程是稀缺资源,如果无限制的创建,不仅会销耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
2、架构
Java 中的线程池是通过 Executor 框架实现的,该框架中用到了 Executor,Executors,ExecutorService,ThreadPoolExecutor 这几个类
3、使用方式
3.1、一池N线程
• 线程池中的线程处于一定的量,可以很好的控制线程的并发量
• 线程可以重复被使用,在显示关闭之前,都将一直存在
• 超出一定量的线程被提交时候需在队列中等待
3.2、一池一线程(一个任务一个任务执行)
线程池中最多执行 1 个线程,之后提交的线程活动将会排在队列中以此
执行
3.3、可扩容线程池(线程池根据需求创建线程)
• 线程池中数量没有固定,可达到最大值(Interger. MAX_VALUE)
• 线程池中的线程可进行缓存重复利用和回收(回收默认时间为 1 分钟)
• 当线程池中,没有可用线程,会重新创建一个线程
public class ExecutorDemo
public static void main(String[] args)
//一池N线程
ExecutorService threadPool1 = Executors.newFixedThreadPool(5);
//一池一线程
ExecutorService threadPool2 = Executors.newSingleThreadExecutor();
//一池可扩容线程
ExecutorService threadPool3 = Executors.newCachedThreadPool();
try
for(int i=1;i<=20;i++)
threadPool3.execute(()->
System.out.println(Thread.currentThread().getName()+" 办理业务");
);
catch (Exception e)
e.printStackTrace();
finally
threadPool3.shutdown();
4、底层原理、七个参数、拒绝策略
上述三种线程池内部均使用如下代码创建线程池
public ThreadPoolExecutor(int corePoolSize, //核心线程数量
int maximumPoolSize, //最大线程数量
long keepAliveTime, //非核心线程空闲时的存活时间
TimeUnit unit, //存活时间单位
BlockingQueue<Runnable> workQueue, //存放提交但未执行任务的队列
ThreadFactory threadFactory, //线程工厂
RejectedExecutionHandler handler) // 等待队列满后的拒绝策略
JDK内置的拒绝策略:
- AbortPolicy(默认):直接抛出RejectedExecutionException异常阻止系统正常运行。
- CallerRunsPolicy:“调用者运行”一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,从而降低新任务的流量。
- DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前任务
- DiscardPolicy:该策略默默地丢弃无法处理的任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种策略。
6、工作流程
- 在创建了线程池后,线程池中的线程数为零
- 当调用 execute() 方法添加一个请求任务时,线程池做出如下判断:
- 如果正在运行的线程数量小于 corePoolSize ,那么马上创建线程运行这个任务;
- 如果正在运行的线程数量大于或等于 corePoolSize ,那么将这个任务放入队列;
- 如果队列满了且正在运行的线程数量还小于 maximumPoolSize ,那么还是要创建非核心线程立即运行这个任务;
- 如果队列满了且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会启动饱和拒绝策略来执行。
- 当一个线程完成任务时,它会从队列中取下一个任务来执行
- 当一个线程无事可做超过一定时间(keepAliveTime)时,线程会判断:
- 如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。
- 所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。
7、自定义线程池
为什么不允许适用不允许 Executors.的方式创建线程池,如下图
如下代码:线程池核心线程数量为2,最大为5,阻塞队列为3.
多运行几次,可以看到拒绝策略AbortPolicy的效果。
public class ThreadPoolDemo1
public static void main(String[] args)
ExecutorService threadService = new ThreadPoolExecutor(2,
5,
2L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
try
for(int i=1;i<=10;i++)
threadService.execute(()->
System.out.println(Thread.currentThread().getName()+" 办理业务");
);
catch (Exception e)
e.printStackTrace();
finally
threadService.shutdown();
以上是关于11_线程池的主要内容,如果未能解决你的问题,请参考以下文章