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
分享
二维码
< <上一篇
下一篇>>