集合源码学习(四):Vector

Vector是什么?

Vector是一个集合,和在实现结构上和ArrayList很相似,包括增加,修改,删除等等操作,和ArrayList实现算法均一致。所以本篇博文不再像前一篇文章集合源码学习(三):ArrayList 般介绍具体实现类型方方面面。所以想继续了解Vector源码读者可以先看ArrayList这篇,再来读这篇就可以了。
而与ArrayList的最大不同点,就是Vector里面的方法都考虑了线程安全,在很多操作方法上都加了synchronized关键字
这篇文章主要分享一些不同与ArrayList特点的地方。

定义头

public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable

同样是可随机访问以及可克隆,继承子AbstractList等。

初始值以及扩容

关于扩容,在数值上和ArrayList并不相同,如果程序员没有指定初值Vector的大小,则默认为10,而在扩容方面,Vector则是用一个capacityIncrement来确定的,同时也要和程序员要求扩容大小来比较,具体看代码及注释:

  /**
     * 初始值为设置值,增长值为0默认
     */
    public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }
    /**
     * 初始值为10,默认增长值为0.
     */
    public Vector() {
        this(10);
    }

接下来是关于扩容方面:
依次调用ensureCapacity,ensureCapacityHelper,grow等方法,中间除了一些边界判断语句,基本都是层层嵌套,这里主要贴出grow方法代码:

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        //由此可见,如果capacityIncrement>0,就会按照cpacityIncrement大小增加,否则就是2个oldCapacity。
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        //如果min比调整后的大小还大,那就按照minCapacity来。
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

Collections里面的线程安全包装方法

Vector里面也有个subList方法来获得子串,但是与ArrayList的实现不同,因为它被设计为线程安全的,所以直接返回了一个线程安全的包装类,这里介绍一下基本原理。
第一步:

public synchronized List<E> subList(int fromIndex, int toIndex) {
        return Collections.synchronizedList(super.subList(fromIndex, toIndex),
                                            this);
    }

接下来进入Collections.synchronized查看:

static <T> List<T> synchronizedList(List<T> list, Object mutex) {
        return (list instanceof RandomAccess ?
                new SynchronizedRandomAccessList<>(list, mutex) :
                new SynchronizedList<>(list, mutex));
    }

返回了一个SynchronizedRandomAccessList,那再去看这个类。

static class SynchronizedRandomAccessList<E>
        extends SynchronizedList<E>
        implements RandomAccess {
        ...

SynchronizedRandomAccessList(List<E> list, Object mutex) {
            super(list, mutex);
        }

这个类完全指示对super的一个包装SynchronizedList,已看名字就知道是一个线程安全类:

    ...
    final List<E> list;

        SynchronizedList(List<E> list) {
            super(list);
            this.list = list;
        }
        SynchronizedList(List<E> list, Object mutex) {
            super(list, mutex);
            this.list = list;
        }

        public boolean equals(Object o) {
            if (this == o)
                return true;
            synchronized (mutex) {return list.equals(o);}
        }
        public int hashCode() {
            synchronized (mutex) {return list.hashCode();}
        }

        public E get(int index) {
            synchronized (mutex) {return list.get(index);}
        }
        public E set(int index, E element) {
            synchronized (mutex) {return list.set(index, element);}
        }
        public void add(int index, E element) {
            synchronized (mutex) {list.add(index, element);}
        }
    ...

可以发现里面有众多方法,并且都是Vector中操作名字相同的方法,指示都是对当前Vector加锁,再进行操作的线程安全方法。
而其中方法实现原理,都是基于适配器模式间接使用Vector来进行操作,这是典型java多态的应用,如果通过debug源码,可以很清楚的看清这一点。
以上就是Collections里面synchronizedList包装方法的原理,其他方法可以类比理解。

Vector里面的Spliterator-VectorSpliterator

或许会有一个疑问,Vector不是线程安全的么?为啥也有Spliterator?
对于Spliterator不懂的读者可以看我这篇文章:集合源码学习(二):Spliterator
Spliterator可是一个支持并行的迭代器啊。
不多说,先看看源码:

  static final class VectorSpliterator<E> implements Spliterator<E> {
        private final Vector<E> list;
        private Object[] array;
        private int index; // current index, modified on advance/split
        private int fence; // -1 until used; then one past last index
        private int expectedModCount; // initialized when fence set
        ...
    这些和ArrayListSpliterator没有特别之处,就不多说
    ...

        public boolean tryAdvance(Consumer<? super E> action) {
            if (action == null)
                throw new NullPointerException();
            int hi = getFence(), i = index;
            if (i < hi) {
                index = i + 1;
                @SuppressWarnings("unchecked") E e = (E)list.elementData[i];
                action.accept(e);
                if (list.modCount != expectedModCount)
                    throw new ConcurrentModificationException();
                return true;
            }
            return false;
        }
        //forEachRemaining方法和tryAdvance原理类似

和ArrayListSpliterator一样,也会有expectedModCount来保证fast-fail机制,防止在通过迭代器遍历的时候,Vector结构突然被改变(add和remove)。而不同的是,VectorSpliterator还传入了一个Object[]数组,java里面数组也是引用类型,也就是把Vector中的elementData传进来了。这样在tryAdvance中,就可以获得Vector中元素了Vector中get方法是同步的),也就可以进行并行的tryAdvance和forEachRemaining操作了。

确实在Vector上收获蛮多喔^^

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值