JAVA 源码之线程安全List

CopyOnWriteArrayList
  • 线程安全版本ArrayList

  • 新增元素

    public boolean add(E e) {
            final ReentrantLock lock = this.lock;
            lock.lock();//进行加锁
            try {
                Object[] elements = getArray();
                int len = elements.length;
                Object[] newElements = Arrays.copyOf(elements, len + 1);//元素组进行拷贝
                newElements[len] = e;//将新元素加入到新数组中
                setArray(newElements);//新数组重新赋值予原数组
                return true;
            } finally {
                lock.unlock();//释放锁
            }
        }
    
    • 每新加一个元素都会发生一次全数组拷贝
    • 通过add(index,element)增加元素类似
    • 类似于ArrayList通过addAll进行批量的增加效率要高于单个加入
  • 元素的删除

        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();
            }
        }
    
    • 发生一次数组对象拷贝
    • 直接移除元素时,先找到其索引,然后通过以上方法进行移除
    • 同样批量删除的效率高于单个删除
  • 内部类

    • COWIterator
      • next 向后访问
      • previous 向前访问
      • nextIndex 查看下一个索引值
      • previousIndex 前一个索引值
      • 不支持操作:remove,set,add
      • 取值过程不进行mod的检查
    • Spliterators.spliterator
    • COWSubList
  • 特点

    • 变更操作基本是先拷贝出一个副本,操作副本完成后,用副本更新原数据
SynchronizedList
  • 线程安全List

  • 在get/set/add/remove/indexOf/sort 内部对象进行加锁处理

            public E get(int index) {
                synchronized (mutex) {return list.get(index);}
            }
    
  • 加锁粒度比较大

两者对比
  • CopyOnWriteArrayList在数据读上占据优势
  • CopyOnWriteArrayList需要更大的内存空间
  • SynchronizedList使用迭代器需要自己进行线程的同步

你可能感兴趣的:(JAVA 源码之线程安全List)