Java 集合深入理解 :线程安全的数组集合(Vector)
Posted 踩踩踩从踩
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 集合深入理解 :线程安全的数组集合(Vector)相关的知识,希望对你有一定的参考价值。
Java 集合深入理解 (三) :java.util 包的集合中 fail-fast 快速失败机制
简介
Vector的字面意思是矢量; 向量;可以用来代替数组,主要不同是vector的长度可以自动增长,那既然是这样,和arraylist有什么区别,主要区别还是在 该应用是java的应用是安全指针!
并是java集合框架在现在已经在官方文档并不推荐使用了,和arraylist一样同样维护一个数组, 但通过加synchronized来保证线程安全,有自己的扩容方式
关键方法时间复杂度
- get() 直接读取第几个下标,复杂度 O(1)
- add(E) 添加元素,直接在后面添加,复杂度O(1)
- add(index, E) 添加元素,在第几个元素后面插入,后面的元素需要向后移动,复杂度O(n)
- remove()删除元素,后面的元素需要逐个移动,复杂度O(n)
示例
public static void main(String[] args) {
System.out.println("--------------Vector--------------");
Vector v=new Vector();
v.add(1);
v.add(2);
v.add(3);
v.add(7);
v.add(5);
v.add(6);
v.stream().forEach(m->{
System.out.println(m);
});
}
--------------Vector--------------
1
2
3
7
5
6
从上面的示例可以看出
- 我们存储的数据是顺序的,遍历出的数据也是按照插入数据取出的
- 虽然我没有写多线程,但是add方法是synchronized修饰的,所以在多线程的情况下数据修改是安全的
全篇注释
/**
*{@code Vector}类实现了一个可增长的对象。与数组一样,它包含可以使用整数索引访问。然而,一个
*{@code Vector}可以根据需要增长或收缩以适应在创建{@code Vector}之后添加和删除项。<p>每个向量都试图通过维护
*{@code capacity}和{@code capacityIncrement}。这个{@code capacity}总是至少和向量一样大尺寸;它通常更大,因为组件添加到
*向量,向量的存储以块的大小增加{@code capacityIncrement}。应用程序可以提高
*在插入大量数据之前向量的容量部件;这减少了增量再分配的数量。
*<p><a name=“fail fast”>java中的fail-fast(快速失败)机制这个类的{@link#iterator()iterator}和
*{@link#lisiterator(int)lisiterator}方法是快速失败的:如果在迭代器运行后的任何时候对向量进行了结构修改
*以任何方式创建,除了通过迭代器自己的{@link ListIterator#remove()remove}或
*{@link ListIterator#add(Object)add}方法,迭代器将抛出{@link ConcurrentModificationException}。因此,面对
*并发修改时,迭代器会快速而干净地失败,而不是而不是冒着武断的、不确定的行为
*未来的时间。返回的{@link Enumerations}{@link#elements()elements}方法是<em>not</em>fail fast。
*<p>请注意,不能保证迭代器的快速失败行为一般说来,不可能在未来作出任何硬性保证
*存在未同步的并发修改。失败快速迭代器
*尽最大努力抛出{@code ConcurrentModificationException}。
*因此,编写依赖于此的程序是错误的其正确性例外:<i>迭代器的快速失败行为
*应仅用于检测错误。</i>
*<p>从Java2平台v1.2开始,这个类被改进为
*实现{@link List}接口,使其成为
*<a href=“{@docRoot}/./technotes/guides/collections/index.html”>
*Java集合框架</a>。与新系列不同
*实现时,{@code Vector}是同步的。如果线程安全
*不需要实现,建议使用{@link
*ArrayList}代替{@code Vector}。
* @author Lee Boynton
* @author Jonathan Payne
* @see Collection
* @see LinkedList
* @since JDK1.0
*/
主要体现在
- vector是动态扩容
- 为保证数据的安全使用快速失败机制
- 并且建议我们如果线程安全不需要实现,则使用arraylist。
实现接口
从接口来看,和arraylist的继承和实现是一致的。
继承自AbstractList
保证线程安全重写并add sublist等方法
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
成员变量
Vector 成员变量
/**
*将向量的分量放入其中的数组缓冲区已存储。向量的容量就是这个数组缓冲区的长度,
*并且至少足够大以包含向量的所有元素。<p>向量中最后一个元素后面的任何数组元素都为空。
*/
protected Object[] elementData;
/**
*此{@code Vector}对象中有效组件的数目。组件{@code elementData[0]}到
*{@code elementData[elementCount-1]}是实际项。@序列号
*/
protected int elementCount;
/**
*向量容量自动计算的量当其大小大于其容量时递增。如果容量增量小于或等于零,则容量
*每次需要生长时,载体的体积都会加倍。
*@序列号
*/
protected int capacityIncrement;
arraylist中的成员变量
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access
不同点
-
vector缺少 序列化优化的transient
-
不同构造方法构造不同的数组的DEFAULTCAPACITY_EMPTY_ELEMENTDATA
-
数组创建时间不同,vector在创建对象时就创建,arraylist则是修改队列是才改变
-
vector默认可以指定容量的增长大小
相同点
都是object数组,初始化容量相同默认10
构造函数
/**
* 构造一个具有指定初始容量和容量增量。
*
* @param initialCapacity initialCapacity向量的初始容量
* @param capacityIncrement capacityIncrement容量的增量
* 向量溢出时增加
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
/**
* Constructs an empty vector so that its internal data array
* has size {@code 10} and its standard capacity increment is
* zero.
*/
public Vector() {
this(10);
}
创建初始化数组,及指定容量增加值
add方法
- 通过 synchronized 关键字去保证多线程下数据的安全
- modCount 记录好每次操作次数
- 在ensureCapacityHelper 中判断容量是否超出直接扩大两倍在来对比大小
- 扩大二倍还是不够,这选择扩大到增加数据所需的大小 ,
- 大于于 Integer.MAX_VALUE - 8,则直接使用 MAX_VALUE ,最后采用 Arrays.copyOf 进行扩容
/**
* 将指定的元素追加到此向量的末尾。
*
* @param e element to be appended to this Vector
* @return {@code true} (as specified by {@link Collection#add})
* @since 1.2
*/
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
/**
*这实现了ensureCapacity的非同步语义。此类中的同步方法可以在内部调用一种在不增加生产成本的情 况下保证生产能力的方法额外的同步。
*
* @see #ensureCapacity(int)
*/
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;
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);
}
subList方法 重写 subList
public synchronized List<E> subList(int fromIndex, int toIndex) {
return Collections.synchronizedList(super.subList(fromIndex, toIndex),
this);
}
这里为保证线程安全,使用Collections.synchronizedList 将该对象包裹起来,保证数据安全
重写了AbstractList 提供的两个迭代器,以此来保证数据安全等
java.util集合结构图
最后
vector都是采用synchronized 作关键字通过对象锁来保证数据安全,这部分我解析的比较少,因为大部分和arraylist差不多,并且实现理解更简单,具体还是看arraylist中的解析,并且在官方文档中 Vector 已经过被弃用了 ,也推荐不使用,所以在业务开发过程中,也别使用vector
以上是关于Java 集合深入理解 :线程安全的数组集合(Vector)的主要内容,如果未能解决你的问题,请参考以下文章
深入理解JAVA集合系列二:ConcurrentHashMap源码解读