cow容器
copy on write 又被成为写时复制(读写分离)容器,
原理就是:
如果向一个数组中添加元素的时候,会将原来的数组复制一份为新的数组,原来的数组不会动,负责读处理,然后在新的数组中进行添加操作,添加完后,将新数组的地址,赋值给原来数组的地址
这种设计的好处是什么呢?
注意上面的操作arr数组本身是无锁的,没有锁,在添加数据的时候,做了额外的复制,此时如果有线程来读数据,那么读取的是老arr的数据,此时arr的地址还没有改呢,在我添加元素的过程无论有多少个线程来读数据,都是读的原来的arr,不是新的arr所以性能很高,读写离,提高了并发的性能,如果再读再复制
注意:
该容器只能保证最终一致性,因为必须等增加完后,才会赋值给新的地址,不能导致实时一致性
CopyOnWriteArrayList
(可以放重复的元素)
核心源码:
CopyOnWriteArraySet
不能放重复的数据,
其实底层就是调用的CopyOnWriteArrayList.addIfbsent()方法(如果不存在则添加,类似Redis中的nSet())方法,
每次在addIfAbsent方法中每次都要对数组进行遍历,所以opy0nWriteArraySet的性能低于Copy0nWriteArrayList
队列(Queue)
先进先出 实现了Collection接口
BlockingQueue(阻塞队列)
继承了Queue接口
非阻塞队列:当队列满的时候,放入第11个元素,数据丢失
非阻塞队列:当队列中没有元素的时候,取数据,得到的是null
阻塞队列:当队列满的时候,放入第11个元素,等待,等待队列中有出队的元素,那么第11个元素再放进去
阻塞队列:当队列中没有元素的时候,取数据,等待,什么时候有元素入队,才可以取出
ArrayBlockingQueue
原理:不支持读写同时操作,底层是一个Object的数组,有两个池:notEmpty:放的是取的线程 noFull:放的是存的线程
工作原理:有两个类似指针光标:putIndex 和 takeIndex 一个是放的时候的索引,一个是取的时候的索引,初始值都是0,当元素添加进来的时候,就把元素放到对应的"0"索引位置上,然后让pustIndex++ 就变成了"1",下次再有元素来的时候,继续++,直到放不下了,放的指针就变成0位置,下一次放的时候又是放到了0的位置上,取的时候也是,先从"0"位置开始取,然后以此类推,直到取完.又回到0位置上,下一次取的时候,又是从0位置上开始取,就这样一直循环.
源码如下:
放元素和取元素,(阻塞的方法)
面试题:
上面的while不可以换为if,因为如果notFull中的线程被激活的瞬间,有其他线程放入元素,那么队列就又满了那么沿着await后面继续执行就不可以,所以一定要反复确定队列是否满的,才能放入元素
LinkedBlockingQueue
支持读写同时操作,并发情况下,效率高。底层基于链表
原理:有两把锁,一个是放的锁,一个是取的锁
源码如下:
阻塞put方法:
SynchronousQueue
队列的长度为0
工作原理:有两个线程从该队列中去取数据,但是这个队列必须先取,再放,相当于直接是两个线程之间直接进行传递数据.
PriorityBlockingQueue
带有优先级的阻塞队列。
优先级队列,意味着队列有先后顺序的,数据有不同的权重。
无界的队列,没有长度限制,但是在你不指定长度的时候,默认初始长度为11,也可以手动指定,当然随着数据不断的加入,底层(底层是数组Obiet)会自动扩容,直到内存全部消耗殆尽了,导致 OutOfMemorvEror内存溢出 程序才会结束
不可以放入null元素的,不允许放入不可比较的对象(导致抛出ClassCastException),对象必须实现内部比较器或者外部比较器
这个优先级队列,并不是在put数据的时候计算谁在前谁在后而是取数据的时候,才真正判断谁在前 谁在后
优先级--》取数据的优先级
DelayQueue
DelayQueue是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其中的对象只能在其到期时才能从队列中取走
当生产者线程调用put之类的方法加入元素时,会触发Delayed接口中的compareTo方法进行排序,也就是说队列中元素的顺序是按到期时间排序的,而非它们进入队列的顺序。排在队列头部的元素是最早到期的,越往后到期时间越晚。
消费者线程查看队列头部的元素,注意是查看不是取出。然后调用元素的qetDelay方法,如果此方法返回的值小0或者等于0,则消费者线程会从队列中取出此元素,并进行处理。如果getDelay方法返回的值大于0,则消费者线程wait返回的时间值后,再从队列头部取出元素,此元素应该已经到期。
注意:不能将null元素放置到这种队列中。
要想使用该队列,必须重写这两个方法
DelayQueue能做什么
1.淘宝订单业务:下单之后如果三十分钟之内没有付款就自动取消订单
2.饿了吗订餐通知:下单成功后60s之后给用户发送短信通知。
3.关闭空闲连接。服务器中,有很多客户端的连接,空闲一段时间之后需要关闭之
4.缓存。缓存中的对象,超过了空闲时间,需要从缓存中移出。
5.任务超时处理。在网络协议滑动窗口请求应答式交互时,处理超时未响应的请求等。