博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java并发面试常识之copyonwrite
阅读量:4921 次
发布时间:2019-06-11

本文共 1825 字,大约阅读时间需要 6 分钟。

今天在网上看到一个问题,问除了加锁之外有没有其他方法来保证线程安全。楼下很多回答copyonwrite机制。这个问题回答有很多,但是copyonwrite的回答有点误导人。

copyonwrite机制

和单词描述的一样,他的实现就是写时复制, 在往集合中添加数据的时候,先拷贝存储的数组,然后添加元素到拷贝好的数组中,然后用现在的数组去替换成员变量的数组(就是get等读取操作读取的数组)。这个机制和读写锁是一样的,但是比读写锁有改进的地方,那就是读取的时候可以写入的 ,这样省去了读写之间的竞争,看了这个过程,你也发现了问题,同时写入的时候怎么办呢,当然果断还是加锁。

java中的copyonwrite

java中提供了两个利用这个机制实现的线程安全集合。copyonwritearraylist,copyonwritearrayset。看名字就大概猜到他们之间的关系,copyonwritearrayset的底层实现是copyonwritearraylist。我们接下来看看java的实现。

public E get(int index) { return get(getArray(), index); }

get的方法就是普通集合的get没有什么特殊的地方,但是成员变量的声明还是有讲究的,是个用volatile声明的数组,这样就保证了读取的那一刻读取的是最新的数据。

private transient volatile Object[] array;

接下来重点就是add方法了。下面的代码可以明显看出是明显需要reentrantlock加锁的,接下来就是复制数据和添加数据的过程,在setArray的过程中,把新的数组赋值给成员变量array(这里是引用的指向,java保证赋值的过程是一个原子操作)。

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(); } }

关于迭代,他采取的是获取传递给迭代器的数组值进行迭代,中间就算加入新的值也迭代不到。在构造函数中就直接赋值给final的成员变量。

private final Object[] snapshot;          private COWIterator(Object[] elements, int initialCursor) { cursor = initialCursor; snapshot = elements; }

适用场景

copyonwrite的机制虽然是线程安全的,但是在add操作的时候不停的拷贝是一件很费时的操作,所以使用到这个集合的时候尽量不要出现频繁的添加操作,而且在迭代的时候数据也是不及时的,数据量少还好说,数据太多的时候,实时性可能就差距很大了。在多读取,少添加的时候,他的效果还是不错的(数据量大无所谓,只要你不添加,他都是好用的)。

 

转载于:https://www.cnblogs.com/651434092qq/p/11131274.html

你可能感兴趣的文章
C++编写Node.js插件(Addon)
查看>>
Excel-漏斗图分析(差异分析)
查看>>
ansible使用5-Variables
查看>>
SpringBoot2.0源码分析(二):整合ActiveMQ分析
查看>>
pickle 模块
查看>>
eclipse中的项目Java build path (Java创建路径)详解
查看>>
Codeforces Round #439 (Div. 2) 题解
查看>>
awk运用
查看>>
python socket 编程之三:长连接、短连接以及心跳
查看>>
小米手机无限重启,两清与三清
查看>>
web.xml加载顺序
查看>>
Error和Exception的区别?
查看>>
Ceph osd 替换
查看>>
Google BigQuery——企业级大数据分析工具
查看>>
解决@@SERVERNAME丢失的问题.sql
查看>>
Android多屏幕适配
查看>>
SQL 行转列
查看>>
对CSS中的Position、Float属性的一些深入探讨
查看>>
前端UI
查看>>
喵哈哈村的括号序列
查看>>