java中SynchronizedList和Vector的区别详解
作者:hollischuang 发布时间:2023-08-23 10:13:12
前言
Vector是java.util包中的一个类。 SynchronizedList是java.util.Collections中的一个静态内部类。
在多线程的场景中可以直接使用Vector类,也可以使用Collections.synchronizedList(List list)方法来返回一个线程安全的List。
那么,到底SynchronizedList和Vector有没有区别,为什么java api要提供这两种线程安全的List的实现方式呢?
首先,我们知道Vector和Arraylist都是List的子类,他们底层的实现都是一样的。所以这里比较如下两个list1和list2的区别:
List<String> list = new ArrayList<String>();
List list2 = Collections.synchronizedList(list);
Vector<String> list1 = new Vector<String>();
一、比较几个重要的方法
1.1 add方法
Vector的实现:
public void add(int index, E element) {
insertElementAt(element, index);
}
public synchronized void insertElementAt(E obj, int index) {
modCount++;
if (index > elementCount) {
throw new ArrayIndexOutOfBoundsException(index
+ " > " + elementCount);
}
ensureCapacityHelper(elementCount + 1);
System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
elementData[index] = obj;
elementCount++;
}
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
synchronizedList的实现:
public void add(int index, E element) {
synchronized (mutex) {
list.add(index, element);
}
}
这里,使用同步代码块的方式调用ArrayList的add()方法。ArrayList的add方法内容如下:
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
从上面两段代码中发现有两处不同:
Vector使用同步方法实现,synchronizedList使用同步代码块实现。
两者的扩充数组容量方式不一样(两者的add方法在扩容方面的差别也就是ArrayList和Vector的差别。)
1.2 remove方法
synchronizedList的实现:
public E remove(int index) {
synchronized (mutex) {return list.remove(index);}
}
ArrayList类的remove方法内容如下:
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
Vector的实现:
public synchronized E remove(int index) {
modCount++;
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = elementData(index);
int numMoved = elementCount - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--elementCount] = null; // Let gc do its work
return oldValue;
}
从remove方法中我们发现除了一个使用同步方法,一个使用同步代码块之外几乎无任何区别。
通过比较其他方法,我们发现,SynchronizedList里面实现的方法几乎都是使用同步代码块包上List的方法。如果该List是ArrayList,那么,SynchronizedList和Vector的一个比较明显区别就是一个使用了同步代码块,一个使用了同步方法。
二、区别分析
数据增长区别
从内部实现机制来讲ArrayList和Vector都是使用数组(Array)来控制集合中的对象。当你向这两种类型中增加元素的时候,如果元素的数目超出了内部数组目前的长度它们都需要扩展内部数组的长度,Vector缺省情况下自动增长原来一倍的数组长度,ArrayList是原来的50%,所以最后你获得的这个集合所占的空间总是比你实际需要的要大。所以如果你要在集合中保存大量的数据那么使用Vector有一些优势,因为你可以通过设置集合的初始化大小来避免不必要的资源开销。
同步代码块和同步方法的区别
同步代码块在锁定的范围上可能比同步方法要小,一般来说锁的范围大小和性能是成反比的。
同步块可以更加精确的控制锁的作用域(锁的作用域就是从锁被获取到其被释放的时间),同步方法的锁的作用域就是整个方法。
静态代码块可以选择对哪个对象加锁,但是静态方法只能给this对象加锁。
因为SynchronizedList只是使用同步代码块包裹了ArrayList的方法,而ArrayList和Vector中同名方法的方法体内容并无太大差异,所以在锁定范围和锁的作用域上两者并无却别。 在锁定的对象区别上,SynchronizedList的同步代码块锁定的是mutex对象,Vector锁定的是this对象。那么mutex对象又是什么呢? 其实SynchronizedList有一个构造函数可以传入一个Object,如果在调用的时候显示的传入一个对象,那么锁定的就是用户传入的对象。如果没有指定,那么锁定的也是this对象。
所以,SynchronizedList和Vector的区别目前为止有两点:
如果使用add方法,那么他们的扩容机制不一样。
SynchronizedList可以指定锁定的对象。
但是,凡事都有但是。 SynchronizedList中实现的类并没有都使用synchronized同步代码块。其中有listIterator和listIterator(int index)并没有做同步处理。但是Vector却对该方法加了方法锁。 所以说,在使用SynchronizedList进行遍历的时候要手动加锁。
但是,但是之后还有但是。
之前的比较都是基于我们将ArrayList转成SynchronizedList。那么如果我们想把LinkedList变成线程安全的,或者说我想要方便在中间插入和删除的同步的链表,那么我可以将已有的LinkedList直接转成 SynchronizedList,而不用改变他的底层数据结构。而这一点是Vector无法做到的,因为他的底层结构就是使用数组实现的,这个是无法更改的。
所以,最后,SynchronizedList和Vector最主要的区别:
SynchronizedList有很好的扩展和兼容功能。他可以将所有的List的子类转成线程安全的类。
使用SynchronizedList的时候,进行遍历时要手动进行同步处理。
SynchronizedList可以指定锁定的对象。
来源:https://github.com/hollischuang/toBeTopJavaer/blob/master/basics/java-basic/synchronizedlist-vector.md
猜你喜欢
- 前言如今多线程编程已成为了现代软件开发中的重要部分,而并发编程中的线程同步问题更是一道难以逾越的坎。在Java语言中,synchronize
- 前言之前用简书的时候一直是在web端,后来下载了客户端,看到了搜索的那个动画,就尝试的去写了,没写之前感觉挺容易的,写了之后,就感觉里面还是
- 一.HashMap 和Hashtable 的区别我们先看2个类的定义 public class Hashtable exten
- 在项目中,分页是一个项目中必不可少的,它可以防止我们从数据库中进行大量数据查询时速度变慢,提高我们的查询效率。1、定义分页模型:PageMo
- 题目要求思路:模拟Javaclass Solution { public int maximumSwap(int
- 配置多个别名 typeAliasesPackage<property name="typeAliasesPackage&qu
- 下面是一个AOP实现的简单例子:首先定义一些业务方法:/** * Created with IntelliJ IDEA. 
- 1、什么是 ThreadLocal:ThreadLocal,即线程本地变量,如果你创建了一个变量,那么访问这个变量的每个线程都会有这个变量的
- 1. 前言Spring除了IOC和DI,还有另一个杀手锏功能——Spring AOP。AOP是一种面
- 寻找到application.yml的读取的操作。从spring.factories 中查看到# Application Listeners
- Handler每个初学Android开发的都绕不开Handler这个“坎”,为什么说是个坎呢,首先这是Android架构的精髓之一,其次大部
- Android之文件数据存储一、文件保存数据介绍Activity提供了openFileOutput()方法可以用于把数据输出到文件中,具体的
- Android 微信摇一摇功能实现,最近学习传感器,就想实现摇一摇的功能,上网查了些资料,就整理下。如有错误,还请指正。开发环境Androi
- 因为工作原因需要读取json文件,最先是使用url方式不符合要求pass。又使用本地方式读取。记录一下方便后期查看。 注:因为资料都是从网上
- 本文实例讲述了Java接口继承和使用接口操作。分享给大家供大家参考,具体如下:一 接口的继承1 点睛接口支持多继承,一个接口可以有多个父接口
- 可以用于简单的过期订单取消支付、7天自动收货场景中1、Spring Boot整合redis 参考https://www.jb51.net/a
- java匿名内部类:1:匿名内部类,匿名内部类也就是没有名字的内部类。2:匿名内部类的作用正因为没有名字,所以匿名内部类只能使用一次,它通常
- 序列化和反序列化Java是面向对象的语言,与其他语言进行交互(比如与前端js进行http通信),需要把对象转化成一种通用的格式比如json(
- 一、缩略图在浏览相册的时候,可能需要生成相应的缩略图。直接上代码:public class ImageUtil { private Logg
- 正确使用并行流,避免共享可变状态错用并行流而产生错误的首要原因,就是使用的算法改变了某些共享状态。下面是另一种实现对前n个自然数求和的方法,