zoukankan      html  css  js  c++  java
  • 学习ArrayList的扩容机制

    基于jdk8
    1.首先我们看new ArrayList中
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    ArrayList底层就是一个Object数组;
    这里DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个静态的空的Object数组,所以ArrayList初始容量实际是0;
    2.add方法
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    private int size;
    这里size默认值为0
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }
    private static final int DEFAULT_CAPACITY = 10;
    默认DEFAULT_CAPACITY容量为10,但是这是在使用add方法时,ArrayList才会进行初始化容量赋值。
    首次加载时,elementData 对象肯定是一个空的Object数组,所以minCapacity = 10;
    3.接下来我们再看看ensureExplicitCapacity这个方法;
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    首次加载时minCapacity = 10,所以minCapacity - elementData.length肯定大于0,然后进行扩容判断
    还有就是当数组大小超过原有容量之后会进行扩容。扩容大小为 old +(old/2) -->1.5倍
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        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);
    }
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    初次加载,oldCapacity = 0,所以newCapacity=0;newCapacity - minCapacity <0,所以最后初始化加载时newCapacity 为10了。
    最后 newCapacity 会与MAX_ARRAY_SIZE进行比较,不能超过Integer的最大值减8
    The maximum size of array to allocate.
    Some VMs reserve some header words in an array.
    Attempts to allocate larger arrays may result in
    OutOfMemoryError: Requested array size exceeds VM limit
    vm虚拟机会在数组中存放一些数据,所以不能等于Integer.MAX_VALUE(2147483647)
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE)?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

    --拓展--

     因为ArrayList底层是一个Object数组,在多线程环境中可以会出现并发争抢的问题,

    java提供三种解决方案:

    1.new Vector jdk1.0就出现的类

    public void add(E e) {
                int i = cursor;
                synchronized (Vector.this) {
                    checkForComodification();
                    Vector.this.add(i, e);
                    expectedModCount = modCount;
                }
                cursor = i + 1;
                lastRet = -1;
            }

    加了synchronized保证add方法线程安全性,但是并发性急剧下降,所以在jdk1.2中才

    会出现ArrayList这个类。

    2.Collections.SynchronizedList(new ArrayList());

     public boolean add(E e) {
                synchronized (mutex) {return c.add(e);}
            }

    3.new CopyOnWriteArrayList();

    private transient volatile Object[] array;

    使用volatile关键字,保证array数组可见性,禁止指令重排;

    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方法添加ReentrantLock 可重入锁(递归锁),保证add方法在多线程环境中程序执行

    的安全性。

     
  • 相关阅读:
    Python面向对象编程及内置方法
    【笨嘴拙舌WINDOWS】SetCapture和ReleaseCapture
    【转】获取屏幕分辨率及大小相关
    【笨嘴拙舌WINDOWS】实践检验之剪切板查看器【Delphi】
    【笨嘴拙舌WINDOWS】剪切板
    【笨嘴拙舌WINDOWS】计时器精度
    【笨嘴拙舌WINDOWS】实践检验之按键精灵【Delphi】
    【笨嘴拙舌WINDOWS】键盘消息,鼠标消息
    【笨嘴拙舌WINDOWS】GDI绘制区域
    【笨嘴拙舌WINDOWS】实践检验之GDI缩放
  • 原文地址:https://www.cnblogs.com/SimonHu1993/p/12026922.html
Copyright © 2011-2022 走看看