设为首页 加入收藏

TOP

Java并发包——线程安全的Collection相关类(一)
2019-09-03 00:51:17 】 浏览:43
Tags:Java 发包 线程 安全 Collection 相关

Java并发包——线程安全的Collection相关类

摘要:本文主要学习了Java并发包下线程安全的Collection相关的类。

部分内容来自以下博客:

https://www.cnblogs.com/skywang12345/p/3498483.html

https://www.cnblogs.com/skywang12345/p/3498652.html

https://www.cnblogs.com/skywang12345/p/3503458.html

https://www.cnblogs.com/skywang12345/p/3498995.html

分类

参照之前在学习集合时候的分类,可以将JUC下有关Collection相关的类进行分类。

CopyOnWriteArrayList:实现了List接口,相当于线程安全的ArrayList。

CopyOnWriteArraySet:继承于AbstractSet类,相当于线程安全的HashSet。CopyOnWriteArraySet内部包含一个CopyOnWriteArrayList对象,它是通过CopyOnWriteArrayList实现的。

ConcurrentSkipListSet:继承于AbstractSet类,相当于线程安全的TreeSet。ConcurrentSkipListSet是通过ConcurrentSkipListMap实现的。

ArrayBlockingQueue:继承于AbstractQueue类,是数组实现的线程安全的有界的阻塞队列。

LinkedBlockingQueue:继承于AbstractQueue类,是单向链表实现的(指定大小)阻塞队列,该队列按FIFO(先进先出)排序元素。

LinkedBlockingDeque:继承于AbstractQueue类,是双向链表实现的(指定大小)双向并发阻塞队列,该阻塞队列同时支持FIFO和FILO两种操作方式。

ConcurrentLinkedQueue:继承于AbstractQueue类,是单向链表实现的无界队列,该队列按FIFO(先进先出)排序元素。

ConcurrentLinkedDeque:继承于AbstractQueue类,是双向链表实现的无界队列,该队列同时支持FIFO和FILO两种操作方式。

CopyOnWriteArrayList

说明

CopyOnWriteArrayList的内部有个“volatile数组”来保持数据。在“添加/修改/删除”数据时,都会新建一个数组,并将更新后的数据拷贝到新建的数组中,最后再将该数组赋值给“volatile数组”,这就是它叫做CopyOnWriteArrayList的原因。CopyOnWriteArrayList就是通过这种方式实现的动态数组,不过正由于它在“添加/修改/删除”数据时,都会新建数组,所以涉及到修改数据的操作,CopyOnWriteArrayList效率很低,但是单单只是进行遍历查找的话,效率比较高。

CopyOnWriteArrayList是通过“volatile数组”来保存数据的。一个线程读取volatile数组时,总能看到其它线程对该volatile变量最后的写入,就这样,通过volatile提供了“读取到的数据总是最新的”这个机制的
保证。

CopyOnWriteArrayList通过互斥锁来保护数据。在“添加/修改/删除”数据时,会先“获取互斥锁”,再修改完毕之后,先将数据更新到“volatile数组”中,然后再“释放互斥锁”,这样,就达到了保护数据的目的。

使用迭代器进行遍历的速度很快,并且不会与其他线程发生冲突。在构造迭代器时,迭代器依赖于不变的数组快照。迭代器支持hasNext()、next()等不可变操作,但不支持add()、remove()等可变操作。

构造方法:

 1 public CopyOnWriteArrayList() {
 2     setArray(new Object[0]);
 3 }
 4 
 5 public CopyOnWriteArrayList(E[] toCopyIn) {
 6     setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
 7 }
 8 
 9 public CopyOnWriteArrayList(Collection<? extends E> c) {
10     Object[] elements;
11     if (c.getClass() == CopyOnWriteArrayList.class)
12         elements = ((CopyOnWriteArrayList<?>)c).getArray();
13     else {
14         elements = c.toArray();
15         // c.toArray might (incorrectly) not return Object[] (see 6260652)
16         if (elements.getClass() != Object[].class)
17             elements = Arrays.copyOf(elements, elements.length, Object[].class);
18     }
19     setArray(elements);
20 }

获取和设置array的方法

array是被volatile和transient修饰的一个数组。

关于volatile关键字,我们知道“volatile能让变量变得可见”,即对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。正在由于这种特性,每次更新了“volatile数组”之后,其它线程都能看到对它所做的更新。

关于transient关键字,它是在序列化中才起作用,transient变量不会被自动序列化。

1 private transient volatile Object[] array;
2 
3 final Object[] getArray() {
4     return array;
5 }
6 
7 final void setArray(Object[] a) {
8     array = a;
9 }

添加元素

因为array数组是volatile修饰的,不能保证线程安全,所以在添加元素时使用锁来保证线程安全。

又因为array数组是volatile修饰的,所以在调用了setArray()方法后,能保证其它线程都能看到新添加的元素。

 1 public void add(int index, E element) {
 2     // 使用锁来保证线程安全。
 3     final ReentrantLock lock = this.lock;
 4     lock.lock();
 5     try {
 6         // 获得array指向的引用地址。
 7         Object[] elements = getArray();
 8         int len = elements.length;
 9         // 如果指定位置越界,则抛出异常。
10         if (index > len || index < 0)
11             throw new IndexOutOfBoundsException("
首页 上一页 1 2 3 4 5 下一页 尾页 1/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇消息中间件介绍(非原创) 下一篇RabbitMQ 消费端限流、TTL、死信..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目