多线程辅助类之数组(一)

xiaoxiao2021-02-27  312

    随着软件技术的不断突飞猛进,针对大数据访问以及并发问题出现了多种各样的技术,例如集群、大数据技术等等。今天我在这边说一下传统的多线程辅助类,方便自己以及一些新手学习。此篇文章说的是数组。我们将普通的数组ArrayList和CopyOnWriteArrayList进行比对分析一下。此篇先铺垫一下ArrayList

    ArrayList分析:

/** * Default initial capacity. */ private static final int DEFAULT_CAPACITY = 10; /** * The size of the ArrayList (the number of elements it contains). * * @serial */    空数组: /** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to * DEFAULT_CAPACITY when the first element is added. */ private transient Object[] elementData; 看一下构造方法:

/** * Constructs an empty list with the specified initial capacity. * * @param initialCapacity the initial capacity of the list * @throws IllegalArgumentException if the specified initial capacity * is negative */ public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; } /** * Constructs an empty list with an initial capacity of ten. */ public ArrayList() { super(); this.elementData = EMPTY_ELEMENTDATA; } /** * Constructs a list containing the elements of the specified * collection, in the order they are returned by the collection's * iterator. * * @param c the collection whose elements are to be placed into this list * @throws NullPointerException if the specified collection is null */ public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); size = elementData.length; // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); }假如我能使用上面的不带长度的构造方法,即ArrayList list = new ArrayList()生成长度为10的list,  接下来我们通过一个简单的add方法这条线,详细的分析一下ArrayList底层实现以及性能分析,加入我们需要add(Object o)

/** * Appends the specified element to the end of this list. * * @param e element to be appended to this list * @return <tt>true</tt> (as specified by {@link Collection#add}) */ public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } 方法 ensureCapacityInternal:找出DEFAULT_CAPACITY和minCapacity中的大值,如果添加到第11个元素,那么list会

private void ensureCapacityInternal(int minCapacity) { if (elementData == EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); }

   ensureExplicitCapacity方法:我们知道

private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }

   追踪grow方法:

/** * Increases the capacity to ensure that it can hold at least the * number of elements specified by the minimum capacity argument. * * @param minCapacity the desired minimum capacity */ private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); //右移运算符,num >> 1,相当于num除以2,大约相当于扩容1.5倍 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } 通过grow方法的最后一行我们发现了elementData = Arrays.copyOf(elementData, newCapacity);接下来通过Apri查询我们知道

static <T> T[]  copyOf(T[] original, int newLength) 复制指定的数组,截取或用 null 填充(如有必要),以使副本具有指定的长度。 如果是这样的实现原理,当遍历操作的数量大大超过可变操作的数量时,这样的实现比较有效,反之,则效率比较低下。 最后,我们在看一下api人注意事项: 注意,此实现不是同步的。如果多个线程同时访问一个 ArrayList 实例,而其中至少一个线程从结构上修改了列表,那么它必须 保持外部同步。(结构上的修改是指任何添加或删除一个或多个元素的操作,或者显式调整底层数组的大小;仅仅设置元素的值不是结构上的修改。)这一般通过对自然封装该列表的对象进行同步操作来完成。如果不存在这样的对象,则应该使用Collections.synchronizedList 方法将该列表“包装”起来。这最好在创建时完成,以防止意外对列表进行不同步的访问:         List list = Collections.synchronizedList(new ArrayList(...));  此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的:在创建迭代器之后,除非通过迭代器自身的remove 或add 方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器都会抛出ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。 注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器会尽最大努力抛出 ConcurrentModificationException。因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅用于检测 bug。

转载请注明原文地址: https://www.6miu.com/read-4199.html

最新回复(0)