基于java构造方法Vevtor添加元素源码分析

(注意:本文基于JDK1.8)

基于java构造方法Vevtor添加元素源码分析_第1张图片

前言

算上迭代器的add()方法,Vector中一共有7个添加元素的方法,5个添加单个元素的方法,2个添加多个元素的方法,接下来就一起分析它们的实现……Vector是一个线程安全的容器类,它的添加功能是如何做到线程安全的呢?

add(E)方法分析

    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }

用于添加1个元素的方法,由synchronized修饰,只有获得对象锁的线程才可以执行该方法,其它未获得对象锁的线程会blocked在方法的入口处,等待已经持有对象锁的线程释放对象锁,传入的参数为即将要添加的元素对象,类型为指定的类型参数E

1、首先修改modCount值

Vecotor的父类AbstractList中,定义了实例变量modCount,这意味着每个Vector对象也持有一个modCount,这里将其+1,表示当前Vector对象持有的元素发生变化,这个modCount值是用于防止用户在多线程下使用容器类而设计的,常被称为fail-fast机制,可Vector本身是线程安全的容器类,为何这里还在使用modCount做++呢?费解……

2、然后检查底层数组容量能否再添加一个新的元素

通过调用ensureCapacityHelper()方法检查,传入参数是实际元素总数+1后的一个值,用于确认当前数组的容量是否需要扩充容量,如果数组的容量无法再添加一个新的元素,则在此方法中会对当前Vector对象持有的数组对象进行容量扩充(扩容的方法,将在单独的文章中分析,这里只需知道,容量不够,先扩容)

3、将元素赋值到数组对象中某个下标处,并增加表示元素总数的实例变量

先使用Vector对象持有的elmentCount作为数组下标,将新增加的元素赋值给elementData数组中对应的下标处,接着将表示实际持有元素的总数值的elementCount增加1,这里的实例变量elementCount同时扮演着两个角色,一个是用于记录Vector对象实际持有的元素总数,另一个是用于作为Vector对象持有的底层数组对象的下标!

4、返回添加元素的结果

每次都会返回true,表示添加元素成功

add(int,E)方法分析

    public void add(int index, E element) {
        insertElementAt(element, index);
    }

用于在指定下标处添加一个元素的方法,第一个参数index表示指定的下标,第二个参数element表示添加的元素

方法体中调用insertElementAt()方法,并将传入的index、element两个参数同时传入insertElementAt()方法中,由insertElementAt()方法完成元素的添加

insertElementAt()方法分析

    public synchronized void insertElementAt(E obj, int index) {
        modCount++;
        if (index > elementCount) {
            throw new ArrayIndexOutOfBoundsException(index
                                                     + " > " + elementCount);
        }
        ensureCapacityHelper(elementCount + 1);
        System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
        elementData[index] = obj;
        elementCount++;
    }

用于在指定下标处添加1个元素的方法,第一参数obj表示添加的元素对象,第二个参数index表示指定的下标……(注意:这里的参数顺序,真是老外思路),同样由synchronized修饰,只有获取到对象锁的线程才能执行该方法,未获取到对象锁的线程处于方法入口处,并处于blocked状态

1、最先修改modCount值

实例变量modCount定义在父类AbstractList中,它用于防止容器类在多线程下使用,常称为fail-fast机制i,此处将该值增加1,表示Vector对象持有的元素发生改变

2、检查传入的下标值是否合法

如果传入的下标值index大于Vector对象实际持有的元素总数elementCount值,此时抛出ArrayIndexOutOfBoundsException对象,并提示用户"index > elementCount"(替换为实际值)

3、检查是否需要扩容

调用ensureCapacityHelper()方法,同时将elementCount+1的值传了进去

4、拷贝数组元素,腾出一个空余位置

通过System的静态方法arraycopy()完成元素的拷贝,arraycopy()的第一个参数为源数组对象,第二个参数为源数组对象的起始下标(从哪个元素开始拷贝),第三个参数为目标数组对象,第四个参数为目标数组对象的起始下标(从哪个元素开始粘贴),第五个参数为需要拷贝的元素数量!此处只需挪出一个位置,即可存放即将要插入的元素!

5、向指定位置插入元素

已经腾出空余空间,只需将元素插入到数组的指定下标处即可

6、元素总数增加

Vector对象持有的elementCount增加1 

addElement()方法分析

    public synchronized void addElement(E obj) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = obj;
    }

同样为synchronized修饰,添加一个元素的方法,有一点和add()方法不同,它没有返回值…………,几乎都一样,这里不再冗余分析

addAll()方法分析

    public synchronized boolean addAll(Collection c) {
        modCount++;
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityHelper(elementCount + numNew);
        System.arraycopy(a, 0, elementData, elementCount, numNew);
        elementCount += numNew;
        return numNew != 0;
    }

 用于添加多个元素的方法,传入的参数为Collection对象,表示持有多个元素的集合对象,本身方法同样是由synchronized修饰

1、为modCount值增加1,表示Vecor对象持有的元素发生改变,fail-fast机制会用到该值

2、先将Collection对象,转换成一个Object[]数组对象,并由局部变量a负责保存

3、获取转换数组后的长度,由局部变量numNew负责保存

4、调用ensureCpacityHelper()方法,将需要的新容量(elementCount+numNew)传入进去,检查现有数组容量能否存储下新的元素数量

5、使用System的静态方法arraycopy(),复制新的元素到旧的数组中,完成添加元素行为

6、更新elementCount总数

7、返回添加结果,只要添加的数量不是0,说明添加元素成功

addAll(int,Collection)方法分析

    public synchronized boolean addAll(int index, Collection c) {
        modCount++;
        if (index < 0 || index > elementCount)
            throw new ArrayIndexOutOfBoundsException(index); 
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityHelper(elementCount + numNew); 
        int numMoved = elementCount - index;
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved); 
        System.arraycopy(a, 0, elementData, index, numNew);
        elementCount += numNew;
        return numNew != 0;
    }

在指定位置添加多个元素的方法,传入的参数index表示指定的下标、传入的参数c表示要添加元素集合对象,同样为synchronized修饰,只有获取到对象锁的线程才能执行该方法,java的线程间同步做的真的太好!

1、更新modCount值,用于fail-fast机制检测

2、检查下标范围是否合法,不合法抛出ArrayIndexOutOfBoundsException提示用户

3、Collection对象转数组对象

4、获取转换后数组对象的长度

5、确认是否需要扩容数组容量

6、计算需要移动元素的数量

7、确定需要移动元素,使用System的静态方法arraycopy()移动元素

8、将新插入的所有元素,都赋值到elementData数组中,就从指定下标index开始

9、更新元素总数值

10、返回添加结果,不为0,即为True

ListItr中的add()方法分析

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

迭代器对象,可以添加元素,必须可以

1、先将遍历到哪个元素的游标保存到局部变量i中

2、只有获取到对象锁的线程,才能执行该代码块,此处仍为当前Vector对象作为对象锁

检查fail-fast机制

使用Vector的add(int,E)方法进行添加元素

更新一个预期值,expetcedModCount,这个也是用于fail-fast机制检测用的

3、更新游标值,增加1

4、更新迭代器对象持有的lastRet值为-1,表示上一次并没有进行遍历元素的行为

总结

1、Vector使用了一手synchronized,这也是导致效率变低的原因

2、假设1个线程执行插入操作需要5s,而其它n个线程操作任意一个Vecotor的方法,因为没有持有当前的Vector对象锁,所有的n个线程都被阻塞了……,同一时刻,只有1个线程能操作Vector的1个方法

3、如果只是读的操作,完全没有必要线程间同步啊,毕竟读的内存值一直没变啊,所以后来大牛不建议使用Vector

以上就是基于java构造方法Vevtor添加元素源码分析的详细内容,更多关于java构造方法Vevtor的资料请关注脚本之家其它相关文章!

你可能感兴趣的