ArrayList和Vector的区别、如何实现线程安全
ArrayList和Vector都是单列集合
首先来说一下Java中集合和数组的区别:
- 集合是可变长的容器,存在自动可扩容机制。数组是定长的,一旦满了,就不能继续添加了。
- 集合只能存储引用类型的元素,而数组既可以存储引用类型的元素,也可以是基本数据类型的元素
- 数组需要一段连续的空间来存储元素,但是一些非基于数组实现的集合是可以不需要连续的内存空间的
Vector和ArrayList的区别
两者都是单列、可变长集合,两者的底层都是基于数组实现的。
- 初始化容量不同:如果使用无参构造来创建两者的实例的话,ArrayList的默认容量是0,Vector的默认初始容量是10
- 扩容机制不同:ArrayList扩容后的容量是上一次的1.5倍,而Vector扩容后是上一次的2倍
- 线程安全不同:ArrayList是线程不安全的,但是Vector所有的方法都使用了synchronized关键字修饰,是线程安全的
- 效率不同:由于Vector使用了synchronized来修饰,所以效率低,ArrayList的效率高。
补充
实际中Vector用的比较少,因为效率问题。
如果在不考虑线程安全的情况下,是可以使用的ArrayList的,ArrayList的使用非常灵活。
常见的ArrayList的使用场景:
- 封装数据库查询结果集
- 集合操作,例如利用stream流对一组数据进行类型转换、过滤等处理时,可以封装到ArrayList中
- 缓存,在一些需要缓存的场景下,可以使用ArrayList来存储数据,操作更高效。
解决
既然ArrayList是线程不安全的,而且Vector效率又很低,那么我在多线程环境下如何利用单列集合来存储数据呢?
可以利用Collections工具类中的synchronizedList()方法,将一个线程不安全的ArrayList转换成一个线程安全的集合。
这个线程安全的集合是Collections的一个静态内部类,这个静态内部类通过synchronized锁了一个锁对象来实现线程安全,效率比synchronized锁一整个方法更高效一些。
// 创建一个普通的ArrayList
List<String> list = new ArrayList<>();
// 转换成一个线程安全的List
List<String> synList = Collections.synchronizedList(list);
// 接下来就可以对synList进行操作
// synList.add(xxx)
// synList.remove(xxxx)
Collections中还可以将线程不安全的LinkedList、Set、Map等实例,转换成线程安全的。
来看看Collections中的静态内部类,看几个经典方法,通过锁一个对象来实现线程安全
static class SynchronizedList<E>
extends SynchronizedCollection<E>
implements List<E> {
//....
public E get(int index) {
synchronized (mutex) {return list.get(index);}
}
public E set(int index, E element) {
synchronized (mutex) {return list.set(index, element);}
}
public void add(int index, E element) {
synchronized (mutex) {list.add(index, element);}
}
public E remove(int index) {
synchronized (mutex) {return list.remove(index);}
}
// ....
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
二维码