Vector源码解析

Vector

源码基于1.8.0_112

Vector使用的相对较少,结构与ArrayList几乎一样。Vector的public方法大多为synchronized,是线程安全的。

原理 :ArrayList内部使用一个数组存储放入的数据,数组使用默认大小初始化(也可以自定义),当数组无法再放入更多的对象时,数组会扩大到原来的2倍或者使用增加扩容系数的大小。

成员变量

大致浏览,结合具体方法来了解具体含义

    // 最重要的一个数组,所有存入Vector的对象都别存入该数组
    protected Object[] elementData;

    // elementData数组中实际存储元素的个数,相当于ArrayList中的size
    protected int elementCount;

    // 每次增加的容量
    protected int capacityIncrement;

    // 数组最大空间,某些虚拟机可能会预留一些数组空间存储元数据,所以空出8位
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    // list被修改的次数,该变量继承于AbstractList
    protected transient int modCount = 0;

构造方法

先阅读默认构造函数,其他构造函数可在阅读完具体操作后再回来阅读

add(E e)

每次加入对象前,会先进行数组大小检查,然后决定是否扩容,详细代码解析可参考 ArrayList
add为同步方法
扩容:
默认 capacityIncrement=0 ,每次扩容为原来的2倍
指定capacityIncrement,则每次增加 capacityIncrement 的大小

图解

这里写图片描述

代码

    /**
     * 添加元素,几乎与ArrayList一样
     * 不同点
     * 1. Vector的add方法为synchronized,线程安全
     * 2. Vector的扩容机制不一样
     *
     * @param e
     * @return
     */
    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }

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

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        // 扩容
        // 默认 capacityIncrement=0 ,所以每次扩容为原来的2倍
        // 指定capacityIncrement,则每次增加 capacityIncrement 的大小
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }

get(int index)

很简单,类似于数组的访问
get为同步方法

代码

    /**
     * 随机访问方法
     * @param index
     * @return
     */
    public synchronized E get(int index) {
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);

        return elementData(index);
    }

    E elementData(int index) {
        return (E) elementData[index];
    }

remove(Object o)

把删除位置之后的数组往前移动一位,并且将最后一位设为null
虽然调用顺寻与ArrayList稍有不同,但是基本逻辑一样
remove为间接的同步方法

图解

这里写图片描述

    /**
     * 删除操作
     * @param o
     * @return
     */
    public boolean remove(Object o) {
        return removeElement(o);
    }

    public synchronized boolean removeElement(Object obj) {
        modCount++;
        // 循环查找到obj的下标
        int i = indexOf(obj);
        if (i >= 0) {
            removeElementAt(i);
            return true;
        }
        return false;
    }

    public int indexOf(Object o) {
        return indexOf(o, 0);
    }

    public synchronized int indexOf(Object o, int index) {
        if (o == null) {
            for (int i = index ; i < elementCount ; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = index ; i < elementCount ; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

    // 把删除位置之后的数组往前移动一位,并且将最后一位设为null
    // 例如,A,B,C,D --> A,C,D,null
    public synchronized void removeElementAt(int index) {
        modCount++;
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " +
                    elementCount);
        }
        else if (index < 0) {
            throw new ArrayIndexOutOfBoundsException(index);
        }
        int j = elementCount - index - 1;
        if (j > 0) {
            System.arraycopy(elementData, index + 1, elementData, index, j);
        }
        elementCount--;
        elementData[elementCount] = null; /* to let gc do its work */
    }

Vector中synchronized对性能的影响

jdk1.6中引入轻量级锁的新型锁机制。
轻量级锁:对象信息中用两位来存储锁状态,通过cas操作来加锁或者解锁。
重量级锁:我们平常所说的锁,会从用户态切换到核态,挂起所有线程。

轻量级锁在没有竞争的情况下具有相当好的性能。但是在存在竞争的情况下轻量级锁加锁失败,则锁会膨胀为重量级锁,两种操作都执行了,效率还不如重量级锁。

这块内容不详细展开(自行阅读《深入理解java虚拟机》),可以简单理解为,在没有多个线程同时操作一个对象的时候,把此操作当做非同步的方法操作。

我们做一个简单的测试
这里写图片描述

十次测试花费的时间几乎一样

// 简单测试代码
public class TestArrayListAndVector {
    public static void main(String[] args) {
        TestArrayListAndVector test = new TestArrayListAndVector();
        for (int i = 0; i < 10; i++) {
            test.testArrayList();
            // test.testVector();
        }
    }

    private void testArrayList() {
        int count = 99999;
        Random random = new Random();
        long start = System.nanoTime();
        List list = new ArrayList();
        for (int i = 0; i < count; i++) {
            list.add(random.nextInt(9999));
        }
        for (int i = 0; i < count; i++) {
            list.get(random.nextInt(9998));
        }
        for (int i = 0; i < count; i++) {
            list.remove(0);
        }
        System.out.println("ArrayList");
        System.out.println(System.nanoTime() - start);
    }

    private void testVector() {
        int count = 99999;
        Random random = new Random();
        long start = System.nanoTime();
        List list = new Vector();
        for (int i = 0; i < count; i++) {
            list.add(random.nextInt(9999));
        }
        for (int i = 0; i < count; i++) {
            list.get(random.nextInt(9998));
        }
        for (int i = 0; i < count; i++) {
            list.remove(0);
        }
        System.out.println("Vector");
        System.out.println(System.nanoTime() - start);
    }

}

总结

  1. Vector中使用了数组,所以随机访问的性能很好
  2. 由于当内部数组容量不足时需要扩容,所以Vector的插入性能一般
  3. 当确定Vector会在短时间内超过某个容量时,可以直接指定初始化的容量,来避免频繁扩容带来的性能损失
  4. Vector的源码几乎与ArrayList一样,只是Vector多数方法为同步方法,保证线程安全
  5. 单线程环境下Vector的性能与ArrayList几乎一样

补充

有位XX小号的吧友提出Vector已经过时,这里再做一点补充

  1. Vector先于List出现,所以设计上有一定的缺陷,并不能与List接口很好的结合(这可能是不推荐使用的重要原因之一)
  2. Vector中使用了大量的同步方法,在线程竞争激烈的情况性能较差(之后再分析SynchronizedList和CopyOnWriteArrayList作为替代集合)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值