JDK1.8源码阅读系列之三:Vector

  

  本篇随笔主要描述的是我阅读 Vector 源码期间的对于 Vector 的一些实现上的个人理解,用于个人备忘,有不对的地方,请指出~

  先来看一下 Vector 的继承图:    可以看出,Vector 的直接父类是 AbstractList(已在JDK1.8源码阅读系列之一介绍过), 直接子类是 Stack(下一篇文章介绍)。

  在 Vector 类源码中,我认为有以下几个地方值得注意:

  1、Vector 类几乎对每一个独立操作(除 Iterator 相关方法)都实现了同步,即在每个方法上几乎都增加了 synchronized 关键字来实现线程间的同步。

  

  2、Vector 扩容方法 grow()

 1  private void grow(int minCapacity) {
 2         // overflow-conscious code
 3         int oldCapacity = elementData.length;
 4         int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
 5                                          capacityIncrement : oldCapacity);
 6         if (newCapacity - minCapacity < 0)
 7             newCapacity = minCapacity;
 8         if (newCapacity - MAX_ARRAY_SIZE > 0)
 9             newCapacity = hugeCapacity(minCapacity);
10         elementData = Arrays.copyOf(elementData, newCapacity);
11 }

 

  可见 Vector 的扩容量是由 oldCapacity 与 capacityIncrement 共同决定的,capacityIncrement 是我们可控的一个参数,在构造方法中传入,即每次容量具体增加多少,如果我们在创建 Vector 对象是没有指定 capacityIncrement,则默认每次把容量增加为原来的二倍(不越界的情况下)。

  3、Vector 类中的 subList()方法我认为值得注意,源码如下:

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

  可见 Vector 调用的是其父类 AbstractList 类中的 subList 方法,并利用 Collections.synchronizedList() 进行装饰,下面看下 Collections.synchronizedList() 方法:

public class Collections {
     ......
    static <T> List<T> synchronizedList(List<T> list, Object mutex) {
        return (list instanceof RandomAccess ?
                new SynchronizedRandomAccessList<>(list, mutex) :
                new SynchronizedList<>(list, mutex));
    }
    static class SynchronizedList<E>
        extends SynchronizedCollection<E>
        implements List<E> {
        private static final long serialVersionUID = -7754090372962971524L;

        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 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);}
        }
        ......
     }
     
     ......
}        

  可见 Collections.synchronizedList() 方法中传入的两个参数 一个是用于底层数组操作的 list,一个是信号量,用于线程间同步。在 vector 类的 subList 方法中,我们传入的参数为 AbstractList 类 subList 方法产生的基于 vector 的 list(对此 list 上进行的操作都会反应到 vector 当中去),还有把 vector 作为信号量参数传入,之所以要把 vector 对象作为信号量,是因为产生的 subList 底层是基于 vector 的,对此 subList 上进行的同步操作应与 vector 上进行的同步操作条件相同,防止同步出现问题。

  4、为什么java Vector类被认为是一个遗留的,过时的或废弃的类?在并发操作时,使用它是无效的吗?

  Vector中对每一个独立操作都实现了同步,这通常不是我们想要的做法。对单一操作实现同步通常不是线程安全的(举个例子,比如你想遍历一个Vector实例。你仍然需要申明一个锁来防止其他线程在同一时刻修改这个Vector实例。如果不添加锁的话通常会在遍历实例的这个线程中导致一个ConcurrentModificationException)同时这个操作也是十分慢的(在创建了一个锁就已经足够的前提下,为什么还需要重复的创建锁)当然,即使你不需要同步,Vector也是有锁的资源开销的。

  总的来说,在大多数情况下,这种同步方法是存在很大缺陷的。正如Mr Brain Henk指出,你可以通过用Collections.synchronizedList来装饰一个集合 ,事实上 ,Vector 将“可变数组”的集合实现与“同步每一个方法”结合起来的做法是另一个糟糕的设计。

  各个装饰方法能够更明确的指示其关注的功能实现。

  对于其子类 Stack ,也可使用双端队列Deque/ArrayDeque来实现栈操作,比如:

  

 1 public static void main(String[] args) {
 2         Deque<Integer> deque = new ArrayDeque<>();
 3         deque.push(1);
 4         deque.push(2);
 5         deque.push(3);
 6         System.out.println(deque.peek());//返回栈顶元素 不删除
 7         System.out.println(deque.size());
 8         while (!deque.isEmpty()) {
 9             System.out.println(deque.pop());
10         }
11 }

 

 

   如果你觉得本篇文章对你有用的话,请随手点击推荐,让更多的人看到,感谢!

  参考:https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/why-is-java-vector-class-considered-obsolete-or-deprecated.md

   

 

posted @ 2017-01-26 17:28  Michaelwjw  阅读(1549)  评论(0编辑  收藏  举报