1
线程池的优点: 1 降低资源消耗,防止频繁创建线程 2 提高响应速度 3 可管理 可延迟定期执行
线程和进程协程的区别 , 进程 不共享堆不共享栈 系统调度 线程 共享堆 不共享栈 系统调度, 协成 代码调度
线程可以并发不可并行
线程池参数
corePoolSize 核心线程数 maximumPoolSize 最大线程数 keepAliveTime 当大于核心线程数时,获取任务中断等待时间
workQueue 暂存任务队列 threadFactory 线程工厂 handler 拒绝策略 (抛异常, 不抛异常, 移除最前面的,放入最后, 调度进程执行)
任务进入,创建线程用Worker包起来, 创建达到核心线程数时, 放入队列, 队列放不下了,创建线程到max, 达到最大就走拒绝策略
之前创建的线程 会在执行完这个任务之后, for 循环 getTask 从队列中拿任务执行, 先判断有任务没,没任务,而且 线程数大于核心,
cas 减去线程数, 返回空的任务, 结束循环, 执行processWorkerExit 线程退出, 从set 移除线程 interruptIdleWorkers
ArrayBlockingQueue
内部是一个对象数组, 包含一把锁。 外加两个唤醒门栓 notFull notEmpty
offer 的时候加锁, 然后 notEmpty.signal 放不进去就返回false
take 加锁 无数据 notEmpty.await 被上面唤醒时 获得值 notFull.signal
put 会被阻塞
image.png
add 放入不成功抛异常 offer 放入不成功返回false put 放不进去会等待
poll null 或 返回值 take 一定要获取到 peek 返回不清空
DelayQueue 延迟queue 获取
放入的元素集成delay
放入的时候按照 delay 值 放入 PriorityQueue 最小顶堆队列, 并且如果当前时第一个唤醒获取的线程
获取的时候 队列为空 等待, 如果delay 小于0 直接返回
否则 等待一定时间后 再循环看返回值
ArrayDeque
双端队列 +++++尾 头 +++
头尾碰到的时候复制两倍
CopyOnWriteArrayList
读写分离
写的时候加锁 复制 移除 添加值 放回 并发读的时候会读到旧的数组
PriorityQueue 二茶最小顶堆
找到最小的值放到堆顶,同时将空缺的位置用堆尾的元素进行占位替换 二分查找
总结
add/offer/put的区别
add 队尾添加抛异常 remove
offer 添加不进去返回false poll
put 添加不进去 阻塞 take
element/peek 用于查询队列的头部元素 不移除
-
put/take方法在****BlockingQueue类型的阻塞队列中使用,可用于多线程对同一数据的同步处理过程中,如数据流的写入与读取等;
-
add/remove/element属于同组方法,对异常操作会抛出异常处理
-
offer/poll/peek属于同组方法,对于异常操作不会跑出异常,只会返回false。
集合框架
[图片上传失败...(image-e1f857-1661335298712)]
简单容器
- vector 安全的list
- ArrayList 对象数组,实现RandomAccess, forEach遍历时使用二分遍历 每次扩容1.5倍
- LinkedList 链表对象串起来,遍历next遍历
- ArrayDeque 双指针分别表明是头和尾,取出放入时根据此调整位置
- HashSet 内部保存了一个HashMap 存储的key为保存的值。value是一个没用的对象
- HashMap 默认16, 达到0.75 容量时扩大2倍 内部保存了Node[] , 每次根据键值计算Hash确定桶位置,放入,冲突就放在上一个的next节点上
- LinkedHashMap 只是使用了Entry 继承了Node 同时多加了两个参数before和after 将他们串起来
- PriorityQueue 最小顶堆,最小的值永远在最上面,每次放入都进行调整
- ArrayBlockingQueue 阻塞队列 生产者消费者, 内部保存数组, 生产满了,wait, 生产后就通知阻塞的消费线程消费
- LinkedBlockingQueue 双锁读写分离 读写各两把锁 因为 是link 两个不影响
- CopyOnWriteArrayList 写的时候加锁 复制一份新的,添加修改, 读取读取旧的值不影响, 读效率高
并发容器
这些容器的关键方法大部分都实现了线程安全的功能,却不使用同步关键字 (synchronized)。值得注意的是 Queue 接口本身定义的几个常用方法的区别,
- add 方法和 offer 方法的区别在于超出容量限制时前者抛出异常,后者返回 false;
- remove 方法和 poll 方法都从队列中拿掉元素并返回,但是他们的区别在于空队列下操作前者抛出异常,而后者返回 null;
- element 方法和 peek 方法都返回队列顶端的元素,但是不把元素从队列中删掉,区别在于前者在空队列的时候抛出异常,后者返回 null。
阻塞队列:
- BlockingQueue.class,阻塞队列接口
- BlockingDeque.class,双端阻塞队列接口
- ArrayBlockingQueue.class,阻塞队列,数组实现
- LinkedBlockingDeque.class,阻塞双端队列,链表实现
- LinkedBlockingQueue.class,阻塞队列,链表实现
- DelayQueue.class,阻塞队列,并且元素是 Delay 的子类,保证元素在达到一定时间后才可以取得到
- PriorityBlockingQueue.class,优先级阻塞队列
- SynchronousQueue.class,同步队列,但是队列长度为 0,生产者放入队列的操作会被阻塞,直到消费者过来取,所以这个队列根本不需要空间存放元素;有点像一个独木桥,一次只能一人通过,还不能在桥上停留
非阻塞队列: - ConcurrentLinkedDeque.class,非阻塞双端队列,链表实现
- ConcurrentLinkedQueue.class,非阻塞队列,链表实现
转移队列: - TransferQueue.class,转移队列接口,生产者要等消费者消费的队列,生产者尝试把元素直接转移给消费者
- LinkedTransferQueue.class,转移队列的链表实现,它比 SynchronousQueue 更快
其它容器: - ConcurrentMap.class,并发 Map 的接口,定义了 putIfAbsent(k,v)、remove(k,v)、replace(k,oldV,newV)、replace(k,v) 这四个并发场景下特定的方法
- ConcurrentHashMap.class,并发 HashMap
- ConcurrentNavigableMap.class,NavigableMap 的实现类,返回最接近的一个元素
- ConcurrentSkipListMap.class,它也是 NavigableMap 的实现类(要求元素之间可以比较),同时它比 ConcurrentHashMap 更加 scalable——ConcurrentHashMap 并不保证它的操作时间,并且你可以自己来调整它的 load factor;但是 ConcurrentSkipListMap 可以保证 O(log n) 的性能,同时不能自己来调整它的并发参数,只有你确实需要快速的遍历操作,并且可以承受额外的插入开销的时候,才去使用它
- ConcurrentSkipListSet.class,和上面类似,只不过 map 变成了 set
- CopyOnWriteArrayList.class,copy-on-write 模式的 array list,每当需要插入元素,不在原 list 上操作,而是会新建立一个 list,适合读远远大于写并且写时间并苛刻的场景
CopyOnWriteArraySet.class,和上面类似,list 变成 set 而已