当前位置:网站首页>并发包和AQS
并发包和AQS
2022-06-12 16:26:00 【-隐函数-】
常用的五种并发包
ConcurrentHashMap
CopyOnWriteArrayList
CopyOnWriteArraySet
ArrayBlockingQueue
LinkedBlockingQueue
并发包就是并发的线程安全的集合
1、ConcurrentHashMap
(1)线程安全的HashMap的实现
(2)数据结构:一个指定个数的Segment数组,数组中的每一个元素Segment相当于一个HashTable(一个HashEntry[])
(3)扩容的话,只需要扩自己的Segment而非整个table扩容
(4)key与value均不可以为null,而hashMap可以
(5)向map添加元素
5.1) 根据key获取key.hashCode的hash值
5.2) 根据hash值算出将要插入的Segment
5.3) 根据hash值与Segment中的HashEntry的容量-1按位与获取将要插入的HashEntry的index
5.4) 若HashEntry[index]中的HashEntry链表有与插入元素相同的key和hash值,根据onlyIfAbsent决定是否替换旧值
5.5) 若没有相同的key和hash,直接返回将新节点插入链头,原来的头节点设为新节点的next(采用的方式与HashMap一致,都是HashEntry替换的方法)
(6)ConcurrentHashMap基于concurrencyLevel划分出多个Segment来存储key-value,这样的话put的时候只锁住当前的Segment,可以避免put的时候锁住整个map,从而减少了并发时的阻塞现象
从map中获取元素
(7)根据key获取key.hashCode的hash值
7.1) 根据hash值与找到相应的Segment
7.2)根据hash值与Segment中的HashEntry的容量-1按位与获取HashEntry的index
7.3)遍历整个HashEntry[index]链表,找出hash和key与给定参数相等的HashEntry,例如e
如没找到e,返回null
如找到e,获取e.value
如果e.value!=null,直接返回
如果e.value==null,则先加锁,等并发的put操作将value设置成功后,再返回value值
(8)对于get操作而言,基本没有锁,只有当找到了e且e.value等于null,有可能是当下的这个HashEntry刚刚被创建,value属性还没有设置成功,这时候我们读到是该HashEntry的value的默认值null,所以这里加锁,等待put结束后,返回value值
(9)加锁情况(分段锁):
---put
---get中找到了hash与key都与指定参数相同的HashEntry,但是value==null的情况
---remove
---size():三次尝试后,还未成功,遍历所有Segment,分别加锁(即建立全局锁)
2、CopyOnWriteArrayList
线程安全且在读操作时无锁的ArrayList
采用的模式就是"CopyOnWrite"(即写操作-->包括增加、删除,使用复制完成)
底层数据结构是一个Object[],初始容量为0,之后每增加一个元素,容量+1,数组复制一遍
遍历的只是全局数组的一个副本,即使全局数组发生了增删改变化,副本也不会变化,所以不会发生并发异常。但是,可能在遍历的过程中读到一些刚刚被删除的对象
增删改上锁、读不上锁
读多写少且脏数据影响不大的并发情况下,选择CopyOnWriteArrayList
3、CopyOnWriteArraySet
基于CopyOnWriteArrayList,不添加重复元素
4、ArrayBlockingQueue
基于数组、先进先出、线程安全,可实现指定时间的阻塞读写,并且容量可以限制
组成:一个对象数组+1把锁ReentrantLock+2个条件Condition
三种入队对比
offer(E e):如果队列没满,立即返回true; 如果队列满了,立即返回false-->不阻塞
put(E e):如果队列满了,一直阻塞,直到数组不满了或者线程被中断-->阻塞
offer(E e, long timeout, TimeUnit unit):在队尾插入一个元素,,如果数组已满,则进入等待,直到出现以下三种情况:-->阻塞
#被唤醒
#等待时间超时
#当前线程被中断
三种出对对比
poll():如果没有元素,直接返回null;如果有元素,出队
take():如果队列空了,一直阻塞,直到数组不为空或者线程被中断-->阻塞
poll(long timeout, TimeUnit unit):如果数组不空,出队;如果数组已空且已经超时,返回null;如果数组已空且时间未超时,则进入等待,直到出现以下三种情况:
#被唤醒
#等待时间超时
#当前线程被中断
需要注意的是,数组是一个必须指定长度的数组,在整个过程中,数组的长度不变,队头随着出入队操作一直循环后移
锁的形式有公平与非公平两种
在只有入队高并发或出队高并发的情况下,因为操作数组,且不需要扩容,性能很高
5、LinkedBlockingQueue
基于链表实现,读写各用一把锁,在高并发读写操作都多的情况下,性能优于ArrayBlockingQueue
组成一个链表+两把锁+两个条件
默认容量为整数最大值,可以看做没有容量限制
三种入队与三种出队与上边完全一样,只是由于LinkedBlockingQueue的的容量无限,在入队过程中,没有阻塞等待
2、AQS

AQS是一个双向链表的队列,内存空间不连续,
举例来说:
现在ConcurrentHashMap集合有两个线程,当两个线程去操作不同的数组索引这个时候是没有问题的,当两个线程去操作同一个索引的时候,就会发生同步问题,这个时候我们就需要用AQS去解决
解决的方式是乐观锁加上公平锁,加上重量级锁
首先先是head这个线程,把state改成1,然后执行,再之后,第二个线程来了,发现锁住就进行阻塞进入到队列之中进行自旋,第三个再来之后就不自旋了就等待了,这就是变成了重量级锁
边栏推荐
- D structure as index of multidimensional array
- acwing 802. 区间和 (离散化)
- The C Programming Language(第 2 版) 笔记 / 8 UNIX 系统接口 / 8.1 文件描述符
- 【BSP视频教程】BSP视频教程第17期:单片机bootloader专题,启动,跳转配置和调试下载的各种用法(2022-06-10)
- <山东大学项目实训>渲染引擎系统(四)
- Batch --03---cmdutil
- acwing 790. 数的三次方根(浮点数二分)
- std::set compare
- In 2021, China's lottery sales generally maintained a rapid growth, and the monthly sales generally tended to be stable [figure]
- 如何基于CCS_V11新建TMS320F28035的工程
猜你喜欢
随机推荐
js监听用户是否打开屏幕焦点
generate pivot data 0
<山东大学项目实训>渲染引擎系统(二)
'virtue and art' in the field of recurrent+transformer video recovery
Global and Chinese market of soft capsule manufacturing equipment 2022-2028: Research Report on technology, participants, trends, market size and share
Comprendre le go des modules go. MOD et go. SUM
盒马,最能代表未来的零售
Cookies and sessions
Thinking about the probability of drawing cards in the duel link of game king
generate pivot data 2
Project training of Shandong University rendering engine system (III)
Kill program errors in the cradle with spotbugs
33-【go】Golang sync. Usage of waitgroup - ensure that the go process is completed before the main process exits
MongoDB系列之SQL和NoSQL的区别
Anfulai embedded weekly report no. 268: May 30, 2022 to June 5, 2022
超详细干货!Docker+PXC+Haproxy搭建高可用强一致性的MySQL集群
acwing794 高精度除法
线程池执行流程
Postgresql源码(53)plpgsql语法解析关键流程、函数分析
面试:为什么整数包装类尽量用equals()来比较大小








