堵塞队列

简介

  • def:在多线程中实现高效、安全的数据传输,主要是通过一个共享的队列,使得数据能够从一端输入,从另一端输出
  • 当队列是空的,取数据的线程就会被堵塞,直到其他线程往空的队列中添加数据
  • 当队列是满的,放数据的线程就会被堵塞,直到其他线程移除数据
  • 使用堵塞队列能够实现简化线程之间的协作,使用生产者消费者模型而不必实现线程间的同步和协作

堵塞队列的分类

1 ArrayBlockingQueue:由数组结构组成的有界堵塞队列
2 LinkedBlockingQueue:由链表结构组成的有界堵塞队列
  • 大小默认值为Integer.MAX_VALUE
3 DelayQueue:使用优先级队列实现的延迟无界的堵塞队列
4 PriorityBlockingQueue:支持优先级排序的无界堵塞队列
5 SynchronousQueue:不存储元素的堵塞队列,也即是单个元素的队列
6 LinkedTransferQueue:由链表结构组成的无界堵塞队列
7 LinkedTransferDeque:由链表结构组成的双向堵塞队列

堵塞队列的常用方法

Thread Pool线程池

简介

  • 线程池是一种线程使用模式,线程池维护者多个线程,可以避免在执行短时间任务创建和销毁线程的代价。
  • 线程池能够保证内核的充分利用,防止过分调度
  • 线程池的主要工作是控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建之后启动这些任务,当任务的数量超过线程数量时,就会将任务放入队列排队等候,等其他线程执行完毕,再从队列中取出任务执行

线程池的特点

  • 降低资源消耗:重复利用自己创建的线程减少创建、销毁的资源消耗
  • 提高响应速度:任务到达的时候,不需要等待线程创建就能直接执行
  • 提高可管理型

线程池的使用

  • Executors.newFilexedThreadPool(int nThreads),创建指定线程数量的线程池

    ExecutorService threadPool1 = Executors.newFixedThreadPool(5);
    try {
    for (int i = 0; i < 10; i++) {
    threadPool1.execute(() -> {
    System.out.println(Thread.currentThread().getName() + " is working...");
    });
    }
    } catch (Exception e) { } finally {
    threadPool1.shutdown();
    }

    pool-1-thread-3 is working...

    pool-1-thread-3 is working...

    pool-1-thread-3 is working...

    pool-1-thread-3 is working...

    pool-1-thread-3 is working...

    pool-1-thread-3 is working...

    pool-1-thread-5 is working...

    pool-1-thread-4 is working...

    pool-1-thread-1 is working...

    pool-1-thread-2 is working...

    Process finished with exit code 0

    只会使用线程池中创建的五个线程去执行任务

  • Executors.newWorkStealingPool(),创建只含有一个线程的线程池

    public static void main(String[] args) {
    ExecutorService threadPool1 = Executors.newSingleThreadExecutor();
    try {
    for (int i = 0; i < 10; i++) {
    threadPool1.execute(() -> {
    System.out.println(Thread.currentThread().getName() + " is working...");
    });
    }
    } catch (Exception e) { } finally {
    threadPool1.shutdown();
    } }

    pool-1-thread-1 is working...

    pool-1-thread-1 is working...

    pool-1-thread-1 is working...

    pool-1-thread-1 is working...

    pool-1-thread-1 is working...

    pool-1-thread-1 is working...

    pool-1-thread-1 is working...

    pool-1-thread-1 is working...

    pool-1-thread-1 is working...

    pool-1-thread-1 is working...

    Process finished with exit code 0

  • Executors.newCachedThreadPool(),创建可扩容的线程池

    public static void main(String[] args) {
    ExecutorService threadPool1 = Executors.newCachedThreadPool();
    try {
    for (int i = 0; i < 10; i++) {
    threadPool1.execute(() -> {
    System.out.println(Thread.currentThread().getName() + " is working...");
    });
    }
    } catch (Exception e) { } finally {
    threadPool1.shutdown();
    }
    }

    pool-1-thread-3 is working...

    pool-1-thread-9 is working...

    pool-1-thread-4 is working...

    pool-1-thread-1 is working...

    pool-1-thread-6 is working...

    pool-1-thread-7 is working...

    pool-1-thread-5 is working...

    pool-1-thread-8 is working...

    pool-1-thread-2 is working...

    pool-1-thread-10 is working...

三种线程池本质都是使用的:

new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>())

线程池的七个参数

    public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
...
}
  1. corePoolSize:核心常驻线程的数量
  2. maximumPoolSize:线程池最大线程数量
  3. keepAliveTime:非核心线程的存活时间
  4. unit:存活时间的单位
  5. workQueue:任务数量超过常驻线程的堵塞队列
  6. threadFactory:线程工厂
  7. handler:线程池拒接策略,即任务数量超过线程池最大线程数量的处理策略

线程池的工作流程和拒绝策略

工作流程

  • 主线程首先通过线程池的execute()方法创建线程
  • 线程数量达到常驻线程的数量,任务就会被放入堵塞队列中
  • 如果堵塞队列也满了,主线程又通过execute()方法创建线程的时候,线程池就会为此任务创建线程并分配(而不是堵塞队列?这里很疑惑)
  • 堵塞队列满了,线程池也满了的时候,主线程再次执行execute()方法,线程池就会去执行拒绝策略
拒绝策略
  1. AbortPolicy(默认):直接抛出RejectExecutionException异常
  2. CallerRunsPolicy:将任务回退给调用者,以降低新任务的流量
  3. DisgardOldestPolicy:抛弃队列中等待最久的任务,而将当前任务添加到队列,尝试再次提交
  4. DiscardPolicy:装死

自定义线程池

为什么要自定义线程池

  1. FixedThreadPool和SingleThreadPool允许的请求队列的大小为Integer.MAX_VALUE,容易造成请求堆积,从而OOM
  2. CachedThreadPool则是允许创建的最大线程数为Integer.MAX_VALUE,会创建大量的线程,从而OOM
public static void main(String[] args) {
var threadPool = new ThreadPoolExecutor(2,
5,
5,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
for (int i = 0; i < 10; i++) {
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + " is working.");
});
}
}
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.hikaru.juc.threadPool.ThreadPoolDemo$$Lambda$14/0x00000008010031f0@7e6cbb7a rejected from java.util.concurrent.ThreadPoolExecutor@4769b07b[Running, pool size = 5, active threads = 5, queued tasks = 3, completed tasks = 0]
at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2081)
at java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:841)
at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1376)
at com.hikaru.juc.threadPool.ThreadPoolDemo.main(ThreadPoolDemo.java:15)
pool-1-thread-4 is working.
pool-1-thread-4 is working.
pool-1-thread-4 is working.
pool-1-thread-4 is working.
pool-1-thread-1 is working.
pool-1-thread-5 is working.
pool-1-thread-3 is working.
pool-1-thread-2 is working.

由于超过了最大线程数5 + 堵塞队列 3,触发了拒绝策略抛出了异常

JUC(六)堵塞队列与线程池的更多相关文章

  1. JUC学习笔记——并发工具线程池

    JUC学习笔记--并发工具线程池 在本系列内容中我们会对JUC做一个系统的学习,本片将会介绍JUC的并发工具线程池 我们会分为以下几部分进行介绍: 线程池介绍 自定义线程池 模式之Worker Thr ...

  2. 自定义ThreadPoolExecutor带Queue缓冲队列的线程池 + JMeter模拟并发下单请求

    .原文:https://blog.csdn.net/u011677147/article/details/80271174 拓展: https://github.com/jwpttcg66/GameT ...

  3. python 线程队列、线程池、全局解释器锁GIL

    一.线程队列 队列特性:取一个值少一个,只能取一次,没有值的时候会阻塞,队列满了,也会阻塞 queue队列 :使用import queue,用法与进程Queue一样 queue is especial ...

  4. 第三十四天- 线程队列、线程池(map/submit/shutdown/回调函数)

    1.线程列队 queue队列 :使用import queue,用法与进程Queue一样 class queue.Queue(maxsize=0) # 先进先出: q = queue.Queue(3) ...

  5. c++之初级的消息队列及线程池模型

    1.最近项目不是很忙,结合之前看的一些开源代码(skynet及其他github代码)及项目代码,抽空写了一个简单的任务队列当做练习. 2.介绍: 1)全局队列中锁的使用:多线程下,全局队列需要加锁,本 ...

  6. C++11消息队列 + Qt线程池 + QRunnable执行任务简单模型

    1.模板类queue,包含头文件<queue>中,是一个FIFO队列. queue.push():在队列尾巴增加数据 queue.pop():移除队列头部数据 queue.font():获 ...

  7. 《数据结构与算法之美》 <07>队列:队列在线程池等有限资源池中的应用?

    我们知道,CPU 资源是有限的,任务的处理速度与线程个数并不是线性正相关.相反,过多的线程反而会导致 CPU 频繁切换,处理性能下降.所以,线程池的大小一般都是综合考虑要处理任务的特点和硬件环境,来事 ...

  8. 【Java并发】并发队列与线程池

    并发队列 阻塞队列与非阻塞队 ConcurrentLinkedQueue BlockingQueue ArrayBlockingQueue LinkedBlockingQueue PriorityBl ...

  9. JUC源码学习笔记5——线程池,FutureTask,Executor框架源码解析

    JUC源码学习笔记5--线程池,FutureTask,Executor框架源码解析 源码基于JDK8 参考了美团技术博客 https://tech.meituan.com/2020/04/02/jav ...

  10. 硬核干货:4W字从源码上分析JUC线程池ThreadPoolExecutor的实现原理

    前提 很早之前就打算看一次JUC线程池ThreadPoolExecutor的源码实现,由于近段时间比较忙,一直没有时间整理出源码分析的文章.之前在分析扩展线程池实现可回调的Future时候曾经提到并发 ...

随机推荐

  1. 使用idea从零编写SpringCloud项目-zuul

    带着问题学习是最好的,什么是网关?使用网关的好处是什么?怎么使用网关 网关:是系统对外的唯一入口,是介于客户端和服务端的中间层,处理非业务功能,提供路由的请求,鉴权,监控,缓存,限流等 网关的好处:可 ...

  2. Informatica常用组件整理

    1. 表达式转换组件 (expression) expression 属于被动组件类型(passive),是一种行级表达式,不改变数据行数,功能强大,操作简单. 主要在以下情况下应用: 对流入数据的类 ...

  3. numpy基本使用(一)

    一.简介  NumPy(Numerical Python) 是用于科学计算及数据处理的Python扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库. 二.数据结构  n ...

  4. JMeter控制器遍历一组数据

    1.获取数据列表,通过JSON提取器提取所有name信息 获取到的name总条数 = name_matchNr = 4 2.通过添加控制器遍历一组数据 2.1 方式一:添加循环控制器 循环控制次数为 ...

  5. animation 和 transition 的区别

    Transition 提供了从一种状态过渡到另一种状态的改变. Animation 则可以从不同关键帧(@keyframes)上设置多个过渡点. Transition 关注的是元素指定css属性的变化 ...

  6. Unity 安装的编辑器版本不见了 记录问题

    新的一天打开unity 报错,然后再打开就找不到我之前安装的编辑器版本了 (猜测是我不正常关闭的原因吧,不懂这个) 之前在网上找到过解决办法,后来找不到了.趁现在还记得,记录一下 先把进程停了 再把缓 ...

  7. auto 类型说明符

    编程时常常需要把表达式的值赋给变量,这就要求在声明变量时清楚地知道表达式的类型.然而做到这一点并非那么容易,有时候甚至根本做不到.为了解决这个问题,c++11新标准引入了auto类型说明符,用它就能让 ...

  8. 什么是js严格模式?

    (use strict)严格模式是一种将更好的错误检查引入代码中的方法. 在使用严格模式时,无法使用隐式声明的变量.将值赋给只读属性或将属性添加到不可扩展的对象等. 1. 严格模式的目的 1) 消除J ...

  9. C#实现控制台打印年历

    C#实现控制台打印年历 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System. ...

  10. git操作回顾,从零入手

    1.可在极狐或者git上直接通过http克隆项目,或者通过ssh密钥,这样就不用每次上传代码需要输入密码和验证 ssh密钥参考如下 (80条消息) git如何生成ssh密钥 git生成配置ssh密钥k ...