重识ArrayList(一)

292 阅读2分钟

前言

作为Java开发,ArrayList最熟悉不过了,但是对它的内部可能了解的不是很透彻,为了更深入的了解ArrayList,最近开始看源码,现在就将看源码学到的一些东西记录下。

1,为什么ArrayList是线程不安全的 大家都知道ArrayList是线程不安全的,可是为什么呢,都说知其然还要知其所以然,我们先看下add()方法

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

首先 其一

elementData[size++] = e;

并不是一个原子操作,是分两步执行的

elementData[size] = e;
size++;

这两步操作在多线程情况下,可能会有如下场景:

  • 1,列表size = 0;
  • 2,线程A执行完elementData[size] = e;之后挂起,A把"a"放在下标为0的位置,此时size=0;
  • 3,线程B执行elementData[size] = e;因为此时size=0,所以B把"b"放在了下标为0的位置,于是刚好把线程A的数据给覆盖屌了。
  • 4,线程B将size值增加为1。
  • 5,线程A将size的值增加为2。 这样的话,线程A的数据被覆盖了,elementData数组里面只有一个元素,线程不安全了。

其次ensureCapacityInternal(size + 1)这个方法的主要作用是判断ArrayList是否需要扩容,需要的话对其进行扩容,假设这种场景

  • 1,数组容量为10,而size为9。
  • 2,线程A执行完其次ensureCapacityInternal(),不需要扩容,然后线程A挂起
  • 3,线程B执行ensureCapacityInternal(),此时size还是9,也不需要扩容,然后B将元素放在下表为9的位置上。size加1为10
  • 4,线程A将元素放在下标为10的位置上,此时数组的总容量只有10,自然没有下标为10的位置,报ArrayIndexOutOfBoundsException,下标越界错误。