注意在学习这一篇之前,需要有多线程的知识:
1)锁机制:对象锁、方法锁、类锁 对象锁就是方法锁:就是在一个类中的方法上加上synchronized关键字,这就是给这个方法加锁了。
类锁:锁的是整个类,当有多个线程来声明这个类的对象的时候将会被阻塞,直到拥有这个类锁的对象
被销毁或者主动释放了类锁。这个时候在被阻塞住的线程被挑选出一个占有该类锁,声明该类的对象。
其他线程继续被阻塞住。例如:在类A上有关键字synchronized,那么就是给类A加了类锁,线程1第一
个声明此类的实例,则线程1拿到了该类锁,线程2在想声明类A的对象,就会被阻塞。2)在本文中,使用的是方法锁。
3)每个对象只有一把锁,有线程A,线程B,还有一个集合C类,线程A操作C拿到了集合中的锁(在集合C中有用synchronized关键字修饰的),并且还没有执行完,那么线程A就不会释放锁,当轮到线程B
去操作集合C中的方法时 ,发现锁被人拿走了,所以线程B只能等待那个拿到锁的线程使用完,然后才能拿到锁进行相应的操作。
Vector
1.Vector是一个可变化长度的数组
2.Vector增加长度通过的是capacity和capacityIncrement这两个变量,目前还不知道如何实现自动扩增的,等会源码分析
3.Vector也可以获得iterator和listIterator这两个迭代器,并且他们发生的是fail-fast,而不是fail- safe,注意这里,不要觉得这个vector是线程安全就搞错了
4.Vector是一个线程安全的类,如果使用需要线程安全就使用Vector,如果不需要,就使用arrayList
5.Vector和ArrayList很类似,就少许的不一样,从它继承的类和实现的接口来看,跟arrayList一模一 样。
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
}
【构造方法】
一共有四个构造方法。最后两个构造方法是collection Framwork的规范要写的构造方法。
构造方法作用:
1.初始化存储元素的容器,也就是数组,elementData,
2.初始化capacityIncrement的大小,默认是0,这个的作用就是扩展数组的时候,增长的大小,为0 则每次扩展2倍
【Vector():空构造】
public Vector() {
this(10);
}
【Vector(int)】
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
【ector(int,int)】
//构建一个有特定的初始化容量和容量增长值的空的Vector,
public Vector(int initialCapacity, int capacityIncrement) { super();//调用父类的构造,是个空构造
if (initialCapacity < 0)//小于0,会报非法参数异常:不合法的容量
throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
this.elementData = new Object[initialCapacity];//elementData是一个成员变量数组,初始化它,并给它初始化长度。默认就是10,除非自己给值。
this.capacityIncrement = capacityIncrement;//capacityIncrement的意思是如果要扩增数组,每次增长该值,如果该值为0,那数组就变为两倍的原长度,这个之后会分析到
}
【Vector(Collection<? extends E> c)】
//将集合c变为Vector,返回Vector的迭代器。
public Vector(Collection<? extends E> c) {
elementData = c.toArray();
elementCount = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, elementCount,Object[].class);
}
核心方法
【add()方法】
public synchronized boolean add(E e) {
modCount++;
//通过arrayList的源码分析经验,这个方法应该是在增加元素前,检查容量是否够用
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
【ensureCapacityHelper(int)】
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
//容量不够,就扩增,核心方法
grow(minCapacity);
}
【grow(int)】
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);
}
这个就是在每个方法上比arrayList多了一个synchronized,其他都一样。
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
Stack
现在来看看Vector的子类Stack,学过数据结构都知道,这个就是栈的意思。那么该类就是跟栈的用法一样了
class Stack<E> extends Vector<E> {}
通过查看他的方法,和查看api文档,很容易就能知道他的特性。就几个操作,出栈,入栈等,构造方法 也是空的,用的还是数组,父类中的构造,跟父类一样的扩增方式,并且它的方法也是同步的,所以也 是线程安全。
【Vector总结】
1.Vector线程安全是因为它的方法都加了synchronized关键字
2.Vector的本质是一个数组,特点能是能够自动扩增,扩增的方式跟capacityIncrement的值有关
3.它也会fail-fast,还有一个fail-safe两个的区别在下面的list总结中会讲到。
【Stack的总结】
1.对栈的一些操作,先进后出
2.底层也是用数组实现的,因为继承了Vector
3.也是线程安全的
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/198015.html