JAVA多线程之——CopyOnWriteArrayList
来源:互联网 发布:华西金手指软件下载 编辑:程序博客网 时间:2024/06/03 15:37
线程安全的list
在学list的时候,应该都了解过ArrayList是线程不安全的集合。今天学习线程安全的一个list集合。CopyOnWriteArrayList。
CopyOnWrite
从取名来看CopyOnWriteArrayList实质上就应该是个ArrayList。只是多了一个CopyOnWrite(写入时复制) 思想是计算机程序设计领域中的一种优化策略。其核心思想是,如果有多个调用者(Callers)同时要求相同的资源(如内存或者是磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者视图修改资源内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。这过程对其他的调用者都是透明的(transparently)。此做法主要的优点是如果调用者没有修改资源,就不会有副本(private copy)被创建,因此多个调用者只是读取操作时可以共享同一份资源。
好在了解了什么是写入时复制思想之后,再来看一下源码的具体实现:
/** The lock protecting all mutators */transient final ReentrantLock lock = new ReentrantLock();/** The array, accessed only via getArray/setArray. */private volatile transient Object[] array;
首先,CopyOnWriteArrayList类中定义了一个ReentrantLock锁,我们知道ReentrantLock是一个可重入的独占锁。 还定义了一个volatile类型的 array。 ArrayList的底层就是基于数组实现。
CopyOnWriteArrayList也也是一样。数组被定义为volatile。是因为volatile定义的变量在多线程环境中可以保证其可见性。声明ReentrantLock就是用来保证线程的安全性。先看读取:
@SuppressWarnings("unchecked")private E get(Object[] a, int index) { return (E) a[index];}/*** {@inheritDoc}** @throws IndexOutOfBoundsException {@inheritDoc}*/public E get(int index) { return get(getArray(), index);}
对于读取而言,很简单,就是读取数组的某一个元素。并没有上锁,这就意味着可以多个线程同时读。
添加/修改/删除
public E set(int index, E element) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); E oldValue = get(elements, index); if (oldValue != element) { int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len); newElements[index] = element; setArray(newElements); } else { // Not quite a no-op; ensures volatile write semantics setArray(elements); } return oldValue; } finally { lock.unlock(); } } public void add(int index, E element) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; if (index > len || index < 0) throw new IndexOutOfBoundsException("Index: "+index+ ", Size: "+len); Object[] newElements; int numMoved = len - index; if (numMoved == 0) newElements = Arrays.copyOf(elements, len + 1); else { newElements = new Object[len + 1]; System.arraycopy(elements, 0, newElements, 0, index); System.arraycopy(elements, index, newElements, index + 1, numMoved); } newElements[index] = element; setArray(newElements); } finally { lock.unlock(); } } public E remove(int index) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; E oldValue = get(elements, index); int numMoved = len - index - 1; if (numMoved == 0) setArray(Arrays.copyOf(elements, len - 1)); else { Object[] newElements = new Object[len - 1]; System.arraycopy(elements, 0, newElements, 0, index); System.arraycopy(elements, index + 1, newElements, index, numMoved); setArray(newElements); } return oldValue; } finally { lock.unlock(); } }
对于修改、删除、添加我们可以看到,都是先上独占锁,然后先把原来的数组复制一份,然后对复制出来的数组进行对应的操作,最后把新的数组赋值给volatile修饰的数组。因为数组是volatile修饰,这就保证了线程在修改之后,其它线程看到的一定是最新值。
缺点
- 在进行修改、删除、添加的时候,都需要对整个数组进行复制,会占用两份内存。如果对象占用的内存较大,就会引发频繁的垃圾回收行为,降低性能;
- CopyOnWrite只能保证数据最终的一致性,不能保证数据的实时一致性。volatile修饰的只保证可见性,不保证原子性。
总结
CopyOnWrite容器来说,只适合在读操作远远多于写操作的场景下使用
- JAVA多线程之——CopyOnWriteArrayList
- JAVA多线程 之 CopyOnWriteArrayList和CopyOnWriteArraySet
- 多线程之-CopyOnWriteArrayList
- Java多线程-----CopyOnWriteArrayList
- Java 多线程之线程安全集合 ConcurrentHashMap、CopyOnWriteArrayList 等
- Java多线程系列--“JUC集合”02之 CopyOnWriteArrayList
- Java多线程系列--“JUC集合”02之 CopyOnWriteArrayList
- Java多线程系列--“JUC集合”02之 CopyOnWriteArrayList
- Java多线程系列--“JUC集合”02之 CopyOnWriteArrayList
- java开发之CopyOnWriteArrayList
- java并发之CopyOnWriteArrayList
- Java技术——CopyOnWriteArrayList源码解析
- Java并发容器——CopyOnWriteArrayList
- Java 并发容器之 CopyOnWriteArrayList
- java并发编程之 CopyOnWriteArrayList
- 多线程-CopyOnWriteArrayList
- 多线程-CopyOnWriteArrayList
- 多线程之操作CopyOnWriteArrayList解决Iterator迭代器产生java.util.ConcurrentModificationException
- Git速查手册(第二版)
- 进度条控件JProgressBar的使用
- 第五届蓝桥杯javaB组—切面条
- 2016年上半年信息系统项目管理师真题之上午题小虎趣味解答第26-30题
- Android透明状态栏与沉浸模式全解
- JAVA多线程之——CopyOnWriteArrayList
- mysql的配置&备份&主从
- FFmpeg常用推流命令
- 蓝桥 李白打酒
- YUV444与YUV422下采样
- 数字调节控件JSpinner的使用
- JavaWeb学习笔记之Servlet
- 看到的高效真正有用的资源
- easyUI(五) -- 分析easyui+mysql实现分页