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);} } // ....
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术