阻塞队列
当队列是空的,从队列中获取元素的操作将会被阻塞
当队列是慢的,从队列中添加元素的操作将会被阻塞
试图从空的队列中获取元素的线程将会被阻塞,直到其他线程往非空的队列插入新的元素
试图向已满的队列中添加新元素的线程将会被阻塞,直到其他线程从队列中移除一个或多个元素或者全部清空,使队列变得空闲起来并后续新增
方法类型 | 抛出异常 | 特殊值 | 阻塞 | 超时 |
---|---|---|---|---|
插入 | add(e) | offer(e) | put(e) | offer(e,time,unit) |
移除 | remove() | poll() | take() | poll(time,unit) |
检查 | element() | peek() | 不可用 | 不可用 |
抛出异常 | 当阻塞队列满时,再往队列中插入元素会抛出IllegalStateException:Queue full;当阻塞队列空时,再remove移除元素会抛出NoSuchElementException |
---|---|
特殊值 | 插入方法,成功true,失败false;移除方法,成功放回队列的元素,队列里没有就返回null |
一直阻塞 | 当阻塞队列满时,生产者线程继续往队列里put元素,队列一直阻塞生产者线程直到put数据or响应中断退出;当阻塞队列空时,消费者试图从队列中take元素时,队列会一直阻塞消费者线程直到队列可用 |
超时退出 | 当阻塞队列满时,队列会阻塞生产者线程一定事件,超时生产者线程会退出 |
线程池七大参数
corePoolSize:
线程池中的常驻核心线程数
maximumPoolSize:
线程池中能够容纳同时执行的最大线程数,此值必须大于等于1
keepAliveTime:
多余的空闲线程存活时间,当前线程池中线程数量超过corePoolSize时,当空闲时间达到keepAliveTime时,多余线程会被销毁直到只剩下corePoolSize个线程为止
unit:
keepAliveTime的单位
workQueue:
任务队列,被提交但未被执行的任务
threadFactory:
表示生成线程池中工作线程的线程工厂,用于创建线程,一般默认的即可
handler:
拒绝策略,表示当前队列满了,并且工作线程大于等于线程池的最大线程数时,如何来拒绝请求执行的runnable的策略
线程池工作原理
1、在创建了线程池后,开始等待请求
2、当调用execute()方法添加一个请求任务时,线程池做出如下判断:
- 如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务
- 如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入队列
- 如果这个时候队列满了且正在运行的线程数量小于maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务
- 如果队列满了且正在运行的线程数量大于或等于maximumPoolSize,纳闷线程池会启动饱和和拒绝策略来执行
3、当一个线程完成任务时,它会从队列中取下一个任务来执行
4、当一个线程无事可做超过一定时间(keepAliveTime)时,线程会判断
- 如果当前线程数大于corePoolSize,那么这个线程就被停掉
- 所以线程池的所有任务完成后,它将收缩到corePoolSize的大小
使用工具创建线程池的三种方式
//创建固定数的线程池
ExecutorService threadPool = Executors.newFixedThreadPool(5);
//创建单一数的线程池
ExecutorService threadPool = Executors.newSingleThreadExecutor();
//创建可变的线程池
ExecutorService threadPool = Executors.newCachedThreadPool();
线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,明确线程池的运行规则,避免资源耗尽的风险
Executors返回线程池对象的弊端
FiedThreadPool和SingleThreadPool:允许的请求队列长度为Integer.Max_VALUE,可能会堆积大量的请求,从而导致OOM
CachedThreadPool和ScheduledThreadPool:允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM
拒绝策略
- AbortPolicy(默认):直接抛出RejecttedExecutionException异常,阻止系统正常运行
- CallerRunsPolicy:“调用者运行”一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,从而降低新任务的流量
- DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前任务
- DiscardPolicy:该策略默默地丢弃无法处理的任务,不予的任何处理不抛出异常,如果允许任务丢失,这是最好的一种策略