`
flashing
  • 浏览: 353233 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

Vector和ArrayList的本质区别到底是什么?

阅读更多

昨天又看人讨论这个问题,发个帖,为新手整理思路,正本清源。

很多人面试、被面试的时候都会被反复问到这个蛋疼的问题:Vector和ArrayList区别是什么?(同理StringBuffer & StringBuilder,Hashtable & HashMap,etc.)

我想很多人都会说出这个以讹传讹了好多年的标准答案:Vector是同步的,ArrayList不是。

其实最主要的核心差别是(抛开API层面的接口关系不讲),JDK1.4之前的这些类,API里面的public函数,都加了synchronized关键字,而JAVA5之后的ArrayList之类的结构,则取消了这个同步关键字限制。

 

取消是必然的,因为这个“同步”,现实在并发环境中起不到作用。

为了把问题简单一点,我们来看一个这样的结构。

public class MyList {
  private int length = 0;

  public synchronized int add(Object newElement) {
    //做添加的操作,blablabla
     length++;
  }

  public synchronized int size() {
    return this.length;
  }
  
}

好的,现在有一个MyList的实例,myList,被某线程的两个实例并发访问,线程A和线程B。

我们看看如果该线程类的实例,线程A和B都执行这样代码:

public void run() {
  if (myList.size() == 0) {
  //BTW:ArrayList里面应该用isEmpty()代替
    myList.add(new Element());
  }

}

 

让我们看看这个MyList类的代码是Thread Safe的吗?假设一个如下的执行顺序:

1.线程A执行myList.size(),这时候线程B也进入了myList.size(),但是只能等线程A的myList.size()执行完毕

2.线程A的myList.size()执行完毕,再没有执行add之前,线程B执行了myList.size()

3.线程A执行了add,无论如何,这时候线程B也要执行add了,因为都满足了myList.size() == 0

run()函数里面的逻辑并没有正确的被执行。

 

synchronized 加在非静态函数上,相当于instance作为锁,即等价于:

synchronized (this) {
 //code...
}

这个锁的粒度非常不好,即难以保证类内部的成员变量在并发下保持一致(如果有多个成员变量的话),也没法保证外面调用者的宏观逻辑是正确的,反倒降低了整体性能。

所以在JAVA5之后,JAVA把这个事情扔给了程序员,数据结构只是作为基础代码存在。

 

更具体的说,很多朋友都知道StringBuilder性能比StringBuffer好不少,其实作为项目整体层面来说,锁和拷贝是降低性能的罪魁祸首,尤其对于性能要求很极端的项目,应该尽量减少不必要的锁和拷贝;当然sun是提供api的,就更不能加入这样的不必要的同步代码了。

 

开发当中,如果一定需要锁,可以为具体的要保护的无关系的成员变量单独分配锁,这样可以保证获得最大的性能。

 

其实JAVA5还提供了很多用于并发的数据结构,比如ConcurrentMap的putIfAbsent就在一个比较好的粒度上给简化了程序员的代码,不会犯前面这个反例的错误。

 

将来,如果在scala、F#等FP语言能够普及,程序员也许不必再考虑这么多的并发问题。

分享到:
评论
26 楼 Crusader 2011-02-25  
NanguoCoffee 写道
LS几位大哥,线程安全的概念是什么呀? 弄清楚没?
我理解的线程概念:
如果某个个类的一个对象,对于能够修改这个对象状态(如add)或者调用其他方法会影响其结果(如get)的任何方法,多线程调用任一方法时,能够保证任意时刻仅有一个线程能执行,
那么这个类就是线程安全的类。


怎么看你这句话都是错的,单CPU有真正意义上的线程"并发"吗?
25 楼 i2534 2011-02-25  
NanguoCoffee 写道
flashing 写道
wwj85523 写道
楼主,你不要在这里误倒新人
多线程编程中,一般用Vector,而不用ArrayList。
除非你自己喜欢写轮子,要自己加锁。


我擦,我都有拿脑袋撞墙的心了。

+1

+1
hashtable和vecotr,我都快忘记还有这些东西了.
1.5的JUC明明提供了更安全,更简单的方式,为什么还要这些老旧的古董呢?
24 楼 youjianbo_han_87 2011-02-25  
本质区别看源码吧。。。。
23 楼 NanguoCoffee 2011-02-25  
flashing 写道
wwj85523 写道
楼主,你不要在这里误倒新人
多线程编程中,一般用Vector,而不用ArrayList。
除非你自己喜欢写轮子,要自己加锁。


我擦,我都有拿脑袋撞墙的心了。

+1
22 楼 flashing 2011-02-25  
wwj85523 写道
楼主,你不要在这里误倒新人
多线程编程中,一般用Vector,而不用ArrayList。
除非你自己喜欢写轮子,要自己加锁。


我擦,我都有拿脑袋撞墙的心了。
21 楼 ironsabre 2011-02-25  
haigui.chen 写道
ironsabre 写道
haigui.chen 写道
谁说Vector线程安全,我和谁急

我觉得你没有真的理解线程安全。

可能是,在put if absent 下面,vector还会是线程安全的么?


vector本身是线程安全的,放在哪都是。
但vector本身的线程安全不能保证你使用了vector的应用程序是线程安全的。
懂了吗?
20 楼 wwj85523 2011-02-25  
楼主,你不要在这里误倒新人
多线程编程中,一般用Vector,而不用ArrayList。
除非你自己喜欢写轮子,要自己加锁。
19 楼 haigui.chen 2011-02-25  
ironsabre 写道
haigui.chen 写道
谁说Vector线程安全,我和谁急

我觉得你没有真的理解线程安全。

可能是,在put if absent 下面,vector还会是线程安全的么?
18 楼 javantsky 2011-02-25  
LZ举的例子是并发编程里面的原子性问题,和vector的线程安全扯在一块容易误导人呀
17 楼 ironsabre 2011-02-25  
haigui.chen 写道
谁说Vector线程安全,我和谁急

我觉得你没有真的理解线程安全。
16 楼 haigui.chen 2011-02-25  
谁说Vector线程安全,我和谁急
15 楼 lewisw 2011-02-25  
ironsabre 写道
lz想表达的应该是:Vector这类api级别的同步,对于实际应用程序来说,意义不大。
你仍然需要在实际应用程序的应用级别再做同步,才能保证应用的线程安全。


说的很对,楼主的问题很有代表性。
14 楼 NanguoCoffee 2011-02-25  
liuningbo 写道
我没记错的话,StringBuffer是基于StringBuider的吧?


像这样的问题,谁都别信,翻翻源码就清楚了。
13 楼 ironsabre 2011-02-25  
lz想表达的应该是:Vector这类api级别的同步,对于实际应用程序来说,意义不大。
你仍然需要在实际应用程序的应用级别再做同步,才能保证应用的线程安全。
12 楼 liuningbo 2011-02-25  
NanguoCoffee 写道
LS几位大哥,线程安全的概念是什么呀? 弄清楚没?
我理解的线程概念:
如果某个个类的一个对象,对于能够修改这个对象状态(如add)或者调用其他方法会影响其结果(如get)的任何方法,多线程调用任一方法时,能够保证任意时刻仅有一个线程能执行,
那么这个类就是线程安全的类。

从这个概念上来说StringBuffer, Vector都是线程安全的。

但是对于
if(!vector.contains(...)){
  vector.add(..)
}

这段代码在多线程情况下并不安全,但不能说:vector不是线程安全的。
因此在:
单线程下:Vector,StringBuffer的线程安全特性是额外的消耗
多线程下:Vector,StringBuffer的线程安全特性在绝大多数情况下不起作用。

因此催生了ArrayList 和StringBuider的出现,并将并发控制交给程序员。

我没记错的话,StringBuffer是基于StringBuider的吧?
11 楼 luciferdevil 2011-02-25  
starcheney 写道
luciferdevil 写道
StringBuffer 和StringBuilder 貌似就是线程安全的差别吧


好像不是哦。。。


StringBuffer: 可改变的Unicode字符序列
允许并发操作,是线程安全的
StringBulder: 可改变的Unicode字符序列
操作同StringBuffer,只是不支持并发操作,非线程安全的

来自:http://miaoge.iteye.com/blog/773784
10 楼 ironsabre 2011-02-25  
LZ你没有明白线程安全是指什么。
比如你的例子,MyList他只要保证同时只有一个线程能进入Add或Size,MyList就是线程安全的。
9 楼 flashing 2011-02-25  
NanguoCoffee 写道
LS几位大哥,线程安全的概念是什么呀? 弄清楚没?
我理解的线程概念:
如果某个个类的一个对象,对于能够修改这个对象状态(如add)或者调用其他方法会影响其结果(如get)的任何方法,多线程调用任一方法时,能够保证任意时刻仅有一个线程能执行,
那么这个类就是线程安全的类。

从这个概念上来说StringBuffer, Vector都是线程安全的。

但是对于
if(!vector.contains(...)){
  vector.add(..)
}

这段代码在多线程情况下并不安全,但不能说:vector不是线程安全的。
因此在:
单线程下:Vector,StringBuffer的线程安全特性是额外的消耗
多线程下:Vector,StringBuffer的线程安全特性在绝大多数情况下不起作用。

因此催生了ArrayList 和StringBuider的出现,并将并发控制交给程序员。

同意。这里可能我表达的稍微有点问题,其实对于对并发理解不够深刻的程序员来说,说vector是线程安全的可能会是一个误导;你说得对,的确在某一个确切的时间点是不存在问题的,但是实际应用中,几乎99%的时候都是:
if(!vector.contains(...)){
  vector.add(..)
}
这种代码,所以vector等结构本身的synchronized就是画蛇添足。

其实最核心的问题是:任何时候程序员写了一个synchronized,都要清楚的知道,这个synchronized到底要保护什么?
8 楼 flashing 2011-02-25  
ahopedog2 写道
第一例子MyList,并不能说明MyList未保证线程安全。原因是调用上的错误,MyList提供的同步是对length,进行的。

这应该使用错误的问题,并不能说明什么。


是的,那个MyList只不过是Vector,StringBuffer等类的代码的一个缩影,的确那是不合理的,是个反例。
7 楼 flashing 2011-02-25  
其实我是就是想说:不是加了个synchronized就是线程安全了,没有任何误导。
Vector的同步完全是没必要的,只能降低性能。
线程安全的关键在于控制的的粒度。

peterwei 写道
引用
我想很多人都会说出这个以讹传讹了好多年的标准答案:Vector是同步的,ArrayList不是。

这有什么错吗?你的文章好像是说这个是错的一样。我认为会误导人。

引用
其实最主要的核心差别是(抛开API层面的接口关系不讲),JDK1.4之前的这些类,API里面的public函数,都加了synchronized关键字,而JAVA5之后的ArrayList之类的结构,则取消了这个同步关键字限制。

那1.4呢?有没有取消?我们谈论的不是版本的区别,而是vector和arraylist,特别是以1.4开始的。

至于线程安全的ArrayList,1.5开始添加了concurrent包,有CopyOnWriteArrayList可用。

我的观点还是:Vector和ArrayList都是基于数组实现的,其中ArrayList是非线程安全的。Vector是基于Synchroinzed实现的线程安全的ArrayList,但在插入元素时容量扩充机制和ArrayList稍有不同,并可通过传入capacityIncrement来控制容量的扩充。

相关推荐

    C++ArrayList

    在C++编程中,`ArrayList`是一个常见的动态数组容器,其设计灵感来源于Java中的ArrayList类。这个类的主要目的是提供一个类似数组的...但在教学或研究场景中,自定义实现ArrayList可以帮助开发者更好地掌握C++的本质。

    链表和数组的区别 数组和链表.pdf

    Vector、ArrayList都是以数组的形式存储在内存中,所以查询效率高,新增和删除效率不高,Vector被Synchronized修饰,所以线程是安全的,ArrayList线程不安全。LinkedList则以链表的形式进行存储,所以查询效率底,...

    java面试笔记.pdf

    1. Vector和ArrayList的区别: - Vector是同步的,适用于线程安全的环境,但因为同步的实现会导致性能损耗。 - Vector在扩容时将容量翻倍,而ArrayList的扩容方式是增加约1.5倍的容量,这使得ArrayList在节约内存...

    最新Java面试宝典pdf版

    59、ArrayList和Vector的区别 44 60、HashMap和Hashtable的区别 44 61、List 和 Map 区别? 45 62、List, Set, Map是否继承自Collection接口? 45 63、List、Map、Set三个接口,存取元素时,各有什么特点? 45 64、说...

    Java面试宝典-经典

    59、ArrayList和Vector的区别 44 60、HashMap和Hashtable的区别 44 61、List 和 Map 区别? 45 62、List, Set, Map是否继承自Collection接口? 45 63、List、Map、Set三个接口,存取元素时,各有什么特点? 45 64、说...

    Java面试宝典2012版

    59、ArrayList和Vector的区别 44 60、HashMap和Hashtable的区别 44 61、List 和 Map 区别? 45 62、List, Set, Map是否继承自Collection接口? 45 63、List、Map、Set三个接口,存取元素时,各有什么特点? 45 64...

    java面试宝典2012

    59、ArrayList和Vector的区别 47 60、HashMap和Hashtable的区别 48 61、List 和 Map 区别? 49 62、List, Set, Map是否继承自Collection接口? 49 63、List、Map、Set三个接口,存取元素时,各有什么特点? 49 64、说...

    完整版 Java初级教程 Java语言程序设计 第8章 集合框架(共19页).ppt

    1. **存储方式**:ArrayList本质上是一个数组,元素存储在连续的内存位置,查询速度较快。 2. **动态扩展**:随着元素的增加,ArrayList会自动扩展其容量。 3. **遍历方式**:支持普通for循环、Iterator迭代器和增强...

    java面试题

    4. 说出ArrayList,Vector,LinkedList的存储性能和特性 8 5. EJB是基于哪些技术实现的?并说出SessionBean和EntityBean的区别,StatefulBean和StatelessBean的区别。 9 6. Collection 和 Collections的区别。 9 7. &...

    链表和数组的区别 (1) 数组和链表.pdf

    ArrayList本质上是动态数组,查询速度快,但插入和删除慢,且线程不安全。LinkedList作为链表实现,查询慢但增删快,同样线程不安全。而Vector是ArrayList的线程安全版本,但其性能较差,因为在多线程环境下,同步...

    技术面试题汇总

    int和Integer有什么区别?** - `int`是基本数据类型,`Integer`是`int`的包装类。 - `int`只能表示整数值,而`Integer`可以表示`null`。 - 在自动装箱和拆箱的情况下,两者可以互相转换。 **4. String和...

    集合类及其分支

    ArrayList本质上是一个动态数组,它允许所有元素,包括null。添加、获取和设置元素的操作具有常量时间复杂度。但是,添加元素的效率为分摊的常数,添加n个元素需要O(n)的时间。ArrayList也是非同步的,需要同步时可...

    Java学习笔记整理

    ArrayList、LinkedList和Vector都是List接口的实现,它们之间的差异在于数据结构和性能:ArrayList适合随机访问,LinkedList适合顺序访问和频繁插入删除,Vector线程安全但效率较低。HashSet和TreeSet是Set接口的...

    华为java面试

    ArrayList和Vector基于数组实现,适合随机访问,但Vector同步方法使其性能较ArrayList低。LinkedList基于双向链表实现,适合频繁插入和删除,但在查找元素时需要遍历,因此效率较低。 多线程编程是Java面试的重点。...

    Java语言常规编程特性浅淡.pdf

    Vector是List集合的另一种类型,其底层实现与ArrayList类似,它们之间的根本区别是ArrayList没有实现线程同步,而Vector则是实现了线程的同步加锁,其在并发的状态下线程是安全的,但在执行的效率上却不如ArrayList...

    杭州面试必看面试题

    Java集合框架中的ArrayList、Vector和LinkedList都是List接口的实现,但它们的存储性能和特性有所不同。ArrayList和Vector都是基于动态数组实现的,它们的查找效率较高,但在添加或删除元素时需要移动数组元素,性能...

Global site tag (gtag.js) - Google Analytics