java集合之Vector

一、介绍

前面我们介绍了java集合中的两种List实现类:基于数组实现的ArrayList和基于双向链表实现的LinkedList,从这两个类的源码中我们注意到,他们的方法实现都是线程不安全的,在多个线程共享一个实例的情况下会出现无法解决的问题。那么我们该如何避免问题的发生以保证线程安全呢?

java为我们提供了一些解决方案:

  • 使用 Collections.synchronizedList(List<T> list)方法,该方法对传入的List对象进行包装,返回一个线程安全的List。保证线程安全的原理就是在我们调用add()remove()等方法时通过使用synchronized代码块对方法进行包装,从而实现线程安全。

    // 线程不安全的List对象
    List<Integer> unSynchronizedList = new ArrayList<>();
    // 线程安全的List对象
    List<Integer> synchronizedList = Collections.synchronizedList(unSynchronizedList);
    
  • 使用CopyOnWriteArrayList,顾名思义,该类采用写入时复制的方法并结合ReentrantLock可重入锁来实现线程安全。

    // 线程安全的List对象
    List<Integer> list = new CopyOnWriteArrayList<>();
    
  • 使用Vector,本篇文章的主角,通过使用synchronized关键字实现线程安全。

    // 线程安全的List对象
    List<Integer> list = new Vector<>();
    

在java的早期版本中,为了解决ArrayList的并发问题,在java1.2中就开始引入了Vector,但是由于synchronized关键字过于重量级且不可控制,容易导致多线程死锁等问题的发生,相当于伤敌一千自损八百,捡了西瓜丢了芝麻。因此从java1.5开始,引入新的保证线程安全的集合实现类CopyOnWriteArrayList

虽然java已经不建议我们使用Vector了,但是由于使用简单,又有哪位同学在并发学习中选择直接绕过它呢?

下面我们看一下Vector的UML图:

在这里插入图片描述

① 实现了List接口,表示实现了List接口所定义的规范

② 继承自AbstractList抽象类,AbstractList同时也实现了List接口,表示继承了AbstractListList默认实现

① 实现了Cloneable接口,表示具有克隆的功能

② 实现了Serializable接口,表示具有序列化的功能

③ 实现了RandomAccess接口,表示具有随机访问的功能

从UML图中可以看出,Vector与ArrayList的继承关系完全一致。因此我们可以先假设这两个类的功能在使用上也完全一致,但要注意的是Vector是线程安全的,而ArrayList是线程不安全的。

注意:上面提到Vector是为了解决ArrayList线程不安全的问题而引入的,我们可以认为Vector是线程安全的ArrayList,在下面的学习中,我们应当将这两个类的不同点作为学习重点。

关于ArrayList源码的学习,请看往期文章:ArrayList源码阅读

二、成员变量

// 对象数组,具有实际意义,用于保存Vector的元素,由此说明Vector是通过数组保存元素的
protected Object[] elementData;
// elementData中对象的数量
protected int elementCount;
// elementData数组在扩容时的增量
protected int capacityIncrement;


// 继承父类AbstractList的变量
// 在使用迭代器遍历过程中,对结构修改的次数,通过该字段可以实现fail-fast快速失败
protected transient int modCount = 0;

三、构造函数

①指定初始容量和扩容增量

// 该构造函数指定Vector实例的初始容量和扩容时的容量的增量
public Vector(int initialCapacity, int capacityIncrement) {
    // 调用父类的无参构造空方法,
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    this.elementData = new Object[initialCapacity];
    this.capacityIncrement = capacityIncrement;
}

②指定初始容量

// 指定初始容量,增量为缺省值0。在扩容部分我们可以看到,当增量为0时,实际增量为原始容量,即扩容后的容量为扩容前的2倍
public Vector(int initialCapacity) {
    this(initialCapacity, 0);
}

③无参构造

// 默认初始容量为10,增量为缺省值0
public Vector() {
    this(10);
}

④通过一个集合构造

// 该构造函数与ArrayList的构造函数的实现一致
public Vector(Collection<? extends E> c) {
    Object[] a = c.toArray();
    elementCount = a.length;
    if (c.getClass() == ArrayList.class) {
        elementData = a;
    } else {
        elementData = Arrays.copyOf(a, elementCount, Object[].class);
    }
}

四、扩容原理

从Vector的源码来看扩容原理,可以发现它的实现与ArrayList的扩容实现几乎完全一致,唯一不同的地方我把源码贴在下面:

// ArrayList的扩容实现, 扩容后的容量为扩容前容量的1.5倍
private void grow(int minCapacity) {
    // ...
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // ...
}

// Vector的扩容实现
// 如果在调用构造函数时指定的扩容增量大于0,则扩容后的容量=扩容前容量+扩容增量
// 否则,扩容后的容量=扩容前容量*2
private void grow(int minCapacity) {
    // ...
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                     capacityIncrement : oldCapacity);
    // ...
}

五、补充说明

Vector从源码上来看,无论是增加元素、删除元素、修改元素、获取元素等方法,与ArrayList大同小异,几乎没有差别,建议读者在学习时以ArrayList作为重点去学习它的源码,然后再以它为参考,对Vector有个基本了解就行了。

再说说面试,Vector的重点知识其实很少很少,一般面试时面试官是不会问的,那么如果问了,可能会找出哪些问题?

①Vector和ArrayList的相同点是什么,不同点是什么,各自的使用场景是什么。

②以Vector线程安全为引子,对synchronized关键字的原理大文特问。

六、Vector和ArrayList的主要对比

相同点不同点
底层结构数组
初始容量10
构造函数1.都可以指定初始容量构造
2.都可以通过集合构造
1.ArrayList有三个,Vector有四个
2.ArrayList可以通过集合、初始容量构造;Vector可以通过集合、初始容量、扩容增量构造
扩容ArrayList扩容后的容量为扩容前容量的1.5倍
Vector扩容后的容量为 扩容前容量+扩容增量扩容前容量*2

至此,java集合中List接口的常用实现ArrayListLinkedListVector已经通关了,接下来我们一起进入Queue接口的实现。

我们下期再会。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

理想万岁万万岁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值