Vector是基于数组实现的随机访问的同步的List结构,其public方法都是加锁的(加锁后不再需要临时变量保持原子性)
Vector的继承关系:
1 2 3
| public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
|
继承了 AbstractList 抽象类,实现了 List 接口,实现了 RandomAccess, Cloneable, java.io.Serializabl e接口,所以支持快速访问、复制(拷贝)、序列化。
查和改操作速度非常快【时间复杂度:O(1)】,增和删操作相对较慢【时间复杂度:最快O(1)最慢O(n)】。
相比于 ArrayList 其效率低,因为加入了 synchronized 操作。
Synchronized:
线程安全是并发编程中的重要关注点,应该注意到的是,造成线程安全问题的主要诱因有两点:
- 一是存在共享数据(也称临界资源)
- 二是存在多条线程共同操作共享数据
为了解决这个问题,我们可能需要这样一个方案,当存在多个线程操作共享数据时,需要保证同一时刻有且只有一个线程在操作共享数据,其他线程必须等到该线程处理完数据后再进行,这种方式有个高尚的名称叫互斥锁,即能达到互斥访问目的的锁,也就是说当一个共享数据被当前正在访问的线程加上互斥锁后,在同一个时刻,其他线程只能处于等待的状态,直到当前线程处理完毕释放该锁。在 Java 中,关键字 synchronized可以保证在同一个时刻,只有一个线程可以执行某个方法或者某个代码块(主要是对方法或者代码块中存在共享数据的操作),同时我们还应该注意到synchronized另外一个重要的作用,synchronized可保证一个线程的变化(主要是共享数据的变化)被其他线程所看到(保证可见性,完全可以替代Volatile功能),这点确实也是很重要的。
synchronized 是悲观锁的实现,因为 synchronized 修饰的代码,每次执行时都会进行加锁操作,同时只允许一个线程进行操作,所以它是悲观锁的实现。
synchronized 是非公平锁,并且是不可设置的。这是因为非公平锁的吞吐量大于公平锁,并且是主流操作系统线程调度的基本选择,所以这也是 synchronized 使用非公平锁原因。
同时,synchronized是一个典型的可重入锁,可重入锁最大的作用是避免死锁。
三大特性:
synchronized保证原子性:
1.通过monitorenter和monitorexit指令,可以保证被synchronized修饰的代码在同一时间只能被一个线程访问,在锁未释放之前,无法被其他线程访问到。
2.即使在执行过程中,由于某种原因,比如CPU时间片用完,线程1放弃了CPU,但是它并没有进行解锁。而由于synchronized的锁是可重入的,这就保证下一个时间片还是只能被他自己获取到,还是会继续执行代码。直到所有代码执行完为止。
synchronized保证可见性:
对于一个被synchronized修饰的变量,在其解锁之前,必须先把此变量同步回主存当中。
synchronized保证有序性:
尽管synchronized无法禁止指令重排和处理器优化,但是可以通过单线程机制来保证有序性。由于synchronized修饰的代码,在同一时刻只能被同一线程访问,从根本上避免了多线程的情况。而单线程环境下,在本线程内观察到的所有操作都是天然有序的,所以synchronized可以通过单线程的方式来保证程序的有序性。
LinkList主要方法分析:
(一)字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| protected Object[] elementData;
protected int elementCount;
protected int capacityIncrement;
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private static final long serialVersionUID = -2767605614048989439L;
|
(二)构造方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public Vector(int initialCapacity, int capacityIncrement) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; this.capacityIncrement = capacityIncrement; }
public Vector(int initialCapacity) { this(initialCapacity, 0); }
public Vector() { this(10); }
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); } }
|
(三)常用方法
扩容算法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| public synchronized void ensureCapacity(int minCapacity) { if (minCapacity > 0) { modCount++; ensureCapacityHelper(minCapacity); } }
private void ensureCapacityHelper(int minCapacity) { if (minCapacity - elementData.length > 0) grow(minCapacity); }
private void grow(int minCapacity) { int oldCapacity = elementData.length;
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) throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
|
一般情况下,扩容分为两种情况,第一种是初始化Vector指定capacityIncrement,且为正数,则每次扩容增加capacityIncrement;另一种情况是,初始化未指定capacityIncrement,则每次扩容的容量翻倍。
转为数组:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public synchronized void copyInto(Object[] anArray) { System.arraycopy(elementData, 0, anArray, 0, elementCount); } public synchronized Object[] toArray() { return Arrays.copyOf(elementData, elementCount); } public synchronized <T> T[] toArray(T[] a) { if (a.length < elementCount) return (T[]) Arrays.copyOf(elementData, elementCount, a.getClass());
System.arraycopy(elementData, 0, a, 0, elementCount);
if (a.length > elementCount) a[elementCount] = null;
return a; }
|
大多数的方法实现思路与ArrayList如出一辙,Vector和ArrayList都是操作数组来实现列表,因此其实现的逻辑基本一致。
常见题
(1)ArrayList和Vector的区别?
相同点:
都实现了List接口。
底层数据结构都是数组。
不同点:
Verctor使用了Synchronized关键字来实现线程同步,所以线程是安全的,而ArrayList是线程不安全的。
在性能方面,因为Verctor很多方法使用了Synchronized关键字进行了加锁操作,所以性能不如ArrayList。
在扩容的时候,ArrayList扩容到原来的1.5倍,而Verctor扩容到原来的2倍。
Vector可以设置增长因子,而ArrayList不可以。
(2)为什么不推荐使用Verctor?
Verctor每个操作方法都加的有synchronized关键字,针对性能来说会比较大的影响,导致它性能很差。