zoukankan      html  css  js  c++  java
  • java并发——copyonwrite

    今天在网上看到一个问题,问除了加锁之外,有没有其他方法来保证线程安全?

    ---- copyonwrite机制

    一、copyonwrite机制

    机制实现:写时复制, 在往集合中添加数据的时候,先拷贝存储的数组,然后添加元素到拷贝好的数组中,然后用现在的数组去替换成员变量的数组。

    这个机制:读写锁是一样的,但是比读写锁有改进的地方,那就是 读取的时候可以写入的 ,这样省去了读写之间的竞争。(同时写入怎么解决?----还是通过加锁)

    二、java中的copyonwrite

    java中提供了两个利用这个机制实现的线程安全集合:

    1、copyonwritearraylist  

    2、copyonwritearrayset  (copyonwritearrayset的底层实现是copyonwritearraylist)

    我们接下来看看java的实现。

        public E get(int index) {
            return get(getArray(), index);
        }
    private transient volatile Object[] array;  //volatile声明的数组,保证了读取的那一刻是最新的数据
    

    接下来重点就是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操作的时候不停的拷贝是一件很费时的操作。

    所以使用到这个集合的时候尽量不要出现频繁的添加操作,而且在迭代的时候,数据也是不及时的,数据量少还好说,数据太多的时候,实时性可能就差距很大了。

    适合:在多读取,少添加的时候,他的效果还是不错的(数据量大无所谓,只要你不添加,他都是好用的)。

  • 相关阅读:
    win7下配置JAVA环境变量
    使用PLSQL Developer和DbVisualizer、SQLDBx查询oracle数据库时出现乱码
    PL/SQL连接ORACLE失败,ORA-12154: TNS: could not resolve the connect identifier specified
    分布式计算开源框架Hadoop入门实践(三)
    分布式计算开源框架Hadoop入门实践(二)
    js使用WebSocket,java使用WebSocket
    springboot管理类,springboot注入类
    博客园点击弹出桃心的js样式、自动落雪花 、复制放进去即可实现
    jquery提交表单 提交form表单
    vue下拉列表
  • 原文地址:https://www.cnblogs.com/651434092qq/p/11131274.html
Copyright © 2011-2022 走看看