文档章节

java并发面试常识之copyonwrite

xpbob
 xpbob
发布于 2016/05/11 22:01
字数 757
阅读 175
收藏 11

        今天在网上看到一个问题,问除了加锁之外有没有其他方法来保证线程安全。楼下很多回答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操作的时候不停的拷贝是一件很费时的操作,所以使用到这个集合的时候尽量不要出现频繁的添加操作,而且在迭代的时候数据也是不及时的,数据量少还好说,数据太多的时候,实时性可能就差距很大了。在多读取,少添加的时候,他的效果还是不错的(数据量大无所谓,只要你不添加,他都是好用的)。

© 著作权归作者所有

共有 人打赏支持
xpbob
粉丝 90
博文 80
码字总数 63415
作品 0
高级程序员
聊聊并发(九)Java中的Copy-On-Write容器

Copy-On-Write简称COW,是一种用于程序设计中的优化策略。其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改...

陶邦仁
2015/03/23
0
0
Java面试:投行的15个多线程和并发面试题

本文由ImportNew -一杯哈希不加盐 翻译自dzone。欢迎加入翻译小组。转载请见文末要求。 多线程和并发问题已成为各种 Java 面试中必不可少的一部分。如果你准备参加投行的 Java 开发岗位面试,...

ImportNew
08/23
0
0
【转】15个顶级Java多线程面试题及回答

Java 线程面试问题   在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分。如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很多关于多线程的问题。在投资银行业务...

一只死笨死笨的猪
2014/09/30
0
0
15个顶级Java多线程面试题及回答

Java 线程面试问题 在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分。如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很多关于多线程的问题。在投资银行业务中多...

LCZ777
2014/05/27
0
0
Java CopyOnWrite容器

Copy-On-Write简称COW(写时复制),是一种程序设计中的优化策略,读取时,直接读取,写入时,copy一个副本,在这个副本上进行写入,写入完成,用副本替换原数据,这是一种延时懒惰策略。 从J...

同明
2014/03/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Hadoop - 企业级大数据管理平台CDH(小技巧一)

附上: 喵了个咪的博客:w-blog.cn cloudera官网: https://www.cloudera.com/ 官方文档地址: https://www.cloudera.com/documentation/enterprise/latest.html 一 , 磁盘扩容磁盘迁移 对于磁盘...

喵了_个咪
26分钟前
1
0
手动安装android的sdk

手动安装android的sdk 用eclipse+sdk的方式开发app,使用android sdk manager无法下载新的sdk,可以手动下载安装。 查找sdk的地址 浏览器访问https://dl-ssl.google.com/android/repository/...

kyle960
26分钟前
1
0
call方法的模拟实现

call方法的模拟实现 初步思考 const person = { name:"小明" } function sayName() { console.log(this.name) } sayName.call(person) //result: 小明 上面的代码有两...

lsner
30分钟前
1
0
apache 报错 AH01089: search for temporary

程序上传文件一直失败。经过测试使用apache反向代理会失败,但是直接访问服务器则可以上传。 经过分析apache的错误日志发现如下提示: apache 报错 AH01089: search for temporary director...

硕硕和果果
35分钟前
2
0
java源码Integer.bitCount算法解析,分析原理

看了一道leetcode上面的题 461 ,Hamming Distance 计算两个整数有多少不同的位。其实很简单,取两个整数异或的值,然后计算出里面二进制有多少个1就行了。代码如下: public int hammi...

117
38分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部