Vector和CopyOnWriteArrayList源码解析
Posted on 2020-04-04 20:37 work hard work smart 阅读(286) 评论(0) 编辑 收藏 举报前面介绍的ArrayList和LinkedList, 在多线程的场景中就不适合了。JDK提供了线程安全的List。
Vector和CopyOnWriteArrayList是线程安全的
1、Vector
这个类属性和方法同ArrayList,主要区别是Vector在其主要方法上都加上了synchronized关键字,这样就达到了线程安全的目的。
2、CopyOnWriteArrayList源码分析
public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { final transient ReentrantLock lock = new ReentrantLock(); //使用数组存储数据 private transient volatile Object[] array; }
相对于ArrayList,多了一个用于线程安全的lock,少了计数size
3、CopyOnWriteArrayList构造函数
//1、空构造函数 public CopyOnWriteArrayList() { setArray(new Object[0]); } //2、集合构造函数 public CopyOnWriteArrayList(Collection<? extends E> c) { Object[] elements; if (c.getClass() == CopyOnWriteArrayList.class) elements = ((CopyOnWriteArrayList<?>)c).getArray(); else { elements = c.toArray(); // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elements.getClass() != Object[].class) elements = Arrays.copyOf(elements, elements.length, Object[].class); } //赋值给当前array setArray(elements); } //3、数字构造函数 public CopyOnWriteArrayList(E[] toCopyIn) { setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class)); } //setArray方法 final void setArray(Object[] a) { array = a; }
主要是将参数解析为一个数字对象,然后复制给array
4、添加操作
//1、添加单个元素 public boolean add(E e) { } //2、添加单个元素到某个位置 public void add(int index, E element) { } //3、添加集合元素 public boolean addAll(Collection<? extends E> c){ } //4、添加集合从某个位置开始 public boolean addAll(int index, Collection<? extends E> c) {
主要分析下public boolean add(E e)
public boolean add(E e) { final ReentrantLock lock = this.lock; //1、获取锁对象 lock.lock(); try { //2、增加元素 Object[] elements = getArray(); int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len + 1); newElements[len] = e; setArray(newElements); return true; } finally { //3、释放锁 lock.unlock(); } }
需要注意的是:CopyOnWriteArrayList并没有ArrayList的自动扩容(1.5倍),添加了一次执行Arrays.copyOf操作,这个会成为性能瓶颈
5、删除操作
我们主要看下
public E remove(int index) { final ReentrantLock lock = this.lock; //1、获取锁 lock.lock(); try { Object[] elements = getArray(); int len = elements.length; E oldValue = get(elements, index); int numMoved = len - index - 1; if (numMoved == 0) setArray(Arrays.copyOf(elements, len - 1)); else { Object[] newElements = new Object[len - 1]; System.arraycopy(elements, 0, newElements, 0, index); System.arraycopy(elements, index + 1, newElements, index, numMoved); setArray(newElements); } return oldValue; } finally { lock.unlock(); } }
6、修改操作
我们看下
public E set(int index, E element) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); E oldValue = get(elements, index); if (oldValue != element) { //直接获取元素,并替换 int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len); newElements[index] = element; setArray(newElements); } else { // Not quite a no-op; ensures volatile write semantics setArray(elements); } return oldValue; } finally { lock.unlock(); } }
7、查询操作
private E get(Object[] a, int index) { return (E) a[index]; } public E get(int index) { return get(getArray(), index); }
这里的get不是线程安全的。
而Vector的查询操作,synchronized 修饰,是线程安全的。
public synchronized E get(int index) { if (index >= elementCount) throw new ArrayIndexOutOfBoundsException(index); return elementData(index); }
总结: 在Vector中,无论增删操作,还是查询操作,统统都加上synchronized锁,
而在CopyOnWriteArrayList中,只有增删改操作添加了锁,查询则没有,使多线程能并行访问。
作者:Work Hard Work Smart
出处:http://www.cnblogs.com/linlf03/
欢迎任何形式的转载,未经作者同意,请保留此段声明!