`
snake1987
  • 浏览: 72751 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

我也来说说Vector跟ArrayList的区别

    博客分类:
  • java
阅读更多
这几天看到论坛首页有一个挺热的帖子Vector和ArrayList的本质区别到底是什么?,正好是自己正在学习的内容,所以也在这发个帖子,献献丑,如有写得不正确的,还希望各位同学斧正

帖子讨论的是面试中常见的Vector,ArrayList以及与其类似的“线程安全类”的问题

里面有几个关键点:
1.线程安全的定义
2.像Vector,HashTable这样几乎在所有方法都添加上"synchronized"能否达到线程安全的效果?(细心点的同学可能还会发现Collections.synchronizedSortedMap,Collections.synchronizedList等是用了同样的手段)
3.Vector到底有没有性能上的问题呢?

天朝人写的东西都没太大的说服力,所以尽量还是引用老外"Doug Lea"的经典《Java Concurrency in Practice》做为论述的依据

关于问题1的解释是这样的

A class is thread-safe if it behaves correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or other coordination on the part of the calling code.

关于问题2呢,首先,需要知道synchronized一个方法到底是一个怎样的操作
解释是这样的:
Java provides a built-in locking mechanism for enforcing atomicity: the synchronized block. (There is also another critical aspect to locking and other synchronization mechanismsvisibilitywhich is covered in Chapter 3.) A synchronized block has two parts: a reference to an object that will serve as the lock, and a block of code to be guarded by that lock. A synchronized method is a shorthand for a synchronized block that spans an entire method body, and whose lock is the object on which the method is being invoked. (Static synchronized methods use the Class object for the lock.)


Every Java object can implicitly act as a lock for purposes of synchronization; these built-in locks are called intrinsic locks or monitor locks. The lock is automatically acquired by the executing thread before entering a synchronized block and automatically released when control exits the synchronized block, whether by the normal control path or by throwing an exception out of the block. The only way to acquire an intrinsic lock is to enter a synchronized block or method guarded by that lock.

也就是说,如果在每个方法前都加上了"synchronized",会起到这样的效果:当一个线程调用任一个该类的方法时,都要先去获取该对象的固有锁"intrinsic lock",然后才进行操作,如果当一个线程正在执行某个方法时,另一个线程也请求进入,那就需要等待前者执行完才能获得锁,然后继续执行

细心的tx想必看出来了,这样会造成严重的效率问题,比如多个线程同时执行get操作,它们根本是不可能相互影响的,但却也需要分别获得锁才能继续执行,单凭这一点就可以为问题3做一个结论了

然后再说说到底能不能达到线程安全的效果呢?
答案也是否定的

看一个例子:
if (!vector.contains(element))
    vector.add(element);

显然,这个操作违背了上文所说的"A class is thread-safe if it behaves correctly when accessed from multiple threads"的效果

然后继续看问题3
The performance cost of synchronization comes from several sources. The visibility guarantees provided by synchronized and volatile may entail using special instructions called memory barriers that can flush or invalidate caches, flush hardware write buffers, and stall execution pipelines. Memory barriers may also have indirect performance consequences because they inhibit other compiler optimizations; most operations cannot be reordered with memory barriers.
从这段话可以看出,synchronized是会影响jvm的优化的,所以问题3的答案也很明确了:
会有性能上的问题

不过对于一些老公司,看到通篇的使用HashTable和Vector,也不必太担忧了
因为:
Modern JVMs can reduce the cost of incidental synchronization by optimizing away locking that can be proven never to contend. If a lock object is accessible only to the current thread, the JVM is permitted to optimize away a lock acquisition because there is no way another thread could synchronize on the same lock.


在这,也顺便为这本经典书打打广告,反正小弟看了是受益匪浅的,有兴趣的tx可以下载看看
分享到:
评论
12 楼 snake1987 2011-03-01  
windrain453 写道

楼主对A class is thread-safe if it behaves correctly when accessed from multiple threads的解释非常误导人。


该解释不是我写的,是jdk并发包的作者做的解释
只是我没有将"behaves correctly"的解释没有摘录下来,原因在之前回复的帖子中已经说明了

下文是关于"behaves correctly"的一个解释:
Correctness means that a class conforms to its specification. A good specification defines invariants constraining an object's state and postconditions describing the effects of its operations. Since we often don't write adequate specifications for our classes, how can we possibly know they are correct? We can't, but that doesn't stop us from using them anyway once we've convinced ourselves that "the code works". This "code confidence" is about as close as many of us get to correctness, so let's just assume that single-threaded correctness is something that "we know it when we see it". Having optimistically defined "correctness" as something that can be recognized, we can now define thread safety in a somewhat less circular way: a class is thread-safe when it continues to behave correctly when accessed from multiple threads.

如果根据该描述,没错,Vector是线程安全的

windrain453 写道

vector是线程安全的,他的方法是同步的,但如果你自己不保证自己的逻辑是线程安全的,那有什么办法。毕竟那些写api的人没法预测你的所有的业务逻辑。


这点倒是说得很对,jdk中提供的某些类:如ConcurrentHashMap之类的,他们都是根据一些常用的场景来制定的锁策略
但在实践中,我们是要根据自己的业务逻辑,来制定自己模块的锁策略,然后根据自己的锁策略,来使用jdk中的类,而不是传说某个类是线程安全的,就盲目去用
11 楼 babby52561 2011-03-01  
synchronize不仅是为了线性执行,还是为了确保线程栈中对象的值被刷新回主内存啊。get方法没有锁的话在多线程下就会发生幻读的情况,而且jdk1.5以后,synchronize的效率已经提升过了吧,性能上和lock类已经差不多了,只不过lock类还有些特殊的用法罢了。
10 楼 分离的北极熊 2011-02-28  
还用看什么书啊,打开源码,1分钟你就知道区别
9 楼 gtssgtss 2011-02-28  
tonynju 写道
对"线程敌意"很好奇,使用场景是什么?

gtssgtss 写道
谈线程安全,得先搞清楚线程安全
线程安全有几个等级:
1,不可变.如String
2,无条件线程安全,指内部的同步机制完整地提供了处理并发的功能,如ConcurrentHashMap
3,有条件线程安全,指内部有同步机制,但是不足以提供完整的处理并发的功能,如Vector
4,线程不安全,指内部没有同步机制,必须对每一个方法调用,以及每一组关联方法调用都进行同步,才能处理并发,如ArrayList
5,线程敌意,外部同步也无法达成线程安全,如System.runFinalizersOnExit



没什么使用场景,这不是什么好东西,出现的原因主要是static字段处理的不好
8 楼 windrain453 2011-02-28  
自己写的业务肯定要自己保证他的正确性啊。

vector是线程安全的,他的方法是同步的,但如果你自己不保证自己的逻辑是线程安全的,那有什么办法。毕竟那些写api的人没法预测你的所有的业务逻辑。

譬如说concurrectHashMap.putIfAbsent(key, value)方法, 其实他也是加了锁的

V put(K key, int hash, V value, boolean onlyIfAbsent) {
            lock();
........................
} finally {
       unlock();
}

其实很多时候明白怎么样运作的是很重要的,而不是一味的用傻瓜方法。

楼主对A class is thread-safe if it behaves correctly when accessed from multiple threads的解释非常误导人。
7 楼 tonynju 2011-02-28  
对"线程敌意"很好奇,使用场景是什么?

gtssgtss 写道
谈线程安全,得先搞清楚线程安全
线程安全有几个等级:
1,不可变.如String
2,无条件线程安全,指内部的同步机制完整地提供了处理并发的功能,如ConcurrentHashMap
3,有条件线程安全,指内部有同步机制,但是不足以提供完整的处理并发的功能,如Vector
4,线程不安全,指内部没有同步机制,必须对每一个方法调用,以及每一组关联方法调用都进行同步,才能处理并发,如ArrayList
5,线程敌意,外部同步也无法达成线程安全,如System.runFinalizersOnExit

6 楼 cantellow 2011-02-28  
<p>通过这个帖子的学习,我明白了一下几点:<br>1.线程安全的定义,线程安全的类只能保证自身method内部数据在多线程情况下安全,而不保证自身method被其它类组合调用时安全,多数情况下,vector的同步意义并没有起多大作用,反而降低效率。<br>2.synchronized关键字的真实含义,访问synchronized方法会获取对象的锁,这时可以同时访问没有synchronized关键字的method,而再访问下一个synchronized方法时,会等待对象释放锁。如果数据是不可变的(没有set),不必同步,一旦有变化,就必须对set和get都实施synchronized关键字。<br>3.线程安全的等级<br><br>一个没有看过<span style="">《Java Concurrency in Practice》并发菜鸟飘过~<span style=""><img src="/images/smiles/icon_cry.gif" alt=""></span></span></p>
5 楼 snake1987 2011-02-28  
topolog 写道
学习了,支持楼主这种专业认真的态度。

但对于下面这句话我有不同理解,如果不对,请指正。
A class is thread-safe if it behaves correctly when accessed from multiple threads

我认为这句话说的是:
当一个class在多线程下访问下,这个class的行为是正确的 就可以说这个class是线程安全的。

重点是对class behaves 的理解,一般我们说 class 的行为是指 class定义的method。
也就是说,如果class定义的method,能在多线程下访问下,正确地执行,就可以说这个class是线程安全的。

还是拿 vector 作为例子,

  • Vector类有add(element)方法,这个method有同步锁,所以这个方法的实现能在多线程下正确执行的。
  • Vector类有contains(element)方法,这个method调用了indexOf()方法, indexOf()方法有同步锁,所以这个方法的实现能在多线程下正确执行的。


按上边thread-safe定义,是可以认为vector 是一个线程安全的class。

主要问题是:一个class的线程安全的,并不能保证把class的行为组合在一起也是线程安全的。
比如你举的例子:

   if (!vector.contains(element))  
        vector.add(element);  


这个例子组合了Vector类的2个行为:contains() 和 add().这是属于Application level 的逻辑, Vector类无法预计它提供的method(行为)会被怎样组合使用。
Vector类只能保证它的单个method(行为)是线程安全的,它不能保证组合它的多个method(行为)也是线程安全的。

所以,从多线程保护来说,Vector class虽然是一个线程安全的class,但是它的提供的多线程保护的效果其实不大。



呵呵,你说的是对的,因为个人主观不太喜欢Vector的滥用现象(现在所在的公司就是如此),所以这里用了点偷换概念的技巧
谢谢指出了,不过还是不打算修改帖子的内容了,呵呵
4 楼 gtssgtss 2011-02-28  
谈线程安全,得先搞清楚线程安全
线程安全有几个等级:
1,不可变.如String
2,无条件线程安全,指内部的同步机制完整地提供了处理并发的功能,如ConcurrentHashMap
3,有条件线程安全,指内部有同步机制,但是不足以提供完整的处理并发的功能,如Vector
4,线程不安全,指内部没有同步机制,必须对每一个方法调用,以及每一组关联方法调用都进行同步,才能处理并发,如ArrayList
5,线程敌意,外部同步也无法达成线程安全,如System.runFinalizersOnExit
3 楼 typhoon466 2011-02-27  
哎呀~~~~~~~受益匪浅呐
2 楼 keke020 2011-02-27  
Vectory是同步的
ArrayList效率高.但不是线程安全的
一般的建议优先使用ArrayList
1 楼 topolog 2011-02-27  
学习了,支持楼主这种专业认真的态度。

但对于下面这句话我有不同理解,如果不对,请指正。
A class is thread-safe if it behaves correctly when accessed from multiple threads

我认为这句话说的是:
当一个class在多线程下访问下,这个class的行为是正确的 就可以说这个class是线程安全的。

重点是对class behaves 的理解,一般我们说 class 的行为是指 class定义的method。
也就是说,如果class定义的method,能在多线程下访问下,正确地执行,就可以说这个class是线程安全的。

还是拿 vector 作为例子,

  • Vector类有add(element)方法,这个method有同步锁,所以这个方法的实现能在多线程下正确执行的。
  • Vector类有contains(element)方法,这个method调用了indexOf()方法, indexOf()方法有同步锁,所以这个方法的实现能在多线程下正确执行的。


按上边thread-safe定义,是可以认为vector 是一个线程安全的class。

主要问题是:一个class的线程安全的,并不能保证把class的行为组合在一起也是线程安全的。
比如你举的例子:

   if (!vector.contains(element))  
        vector.add(element);  


这个例子组合了Vector类的2个行为:contains() 和 add().这是属于Application level 的逻辑, Vector类无法预计它提供的method(行为)会被怎样组合使用。
Vector类只能保证它的单个method(行为)是线程安全的,它不能保证组合它的多个method(行为)也是线程安全的。

所以,从多线程保护来说,Vector class虽然是一个线程安全的class,但是它的提供的多线程保护的效果其实不大。





相关推荐

    Java基础部分 Java代码查错算法与编程html&JavaScript&ajax部分面试题

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

    java软件开发求职试题集合.pdf

    ArrayList和Vector使用数组来存储数据,而LinkedList使用链表来存储数据。ArrayList和Vector的访问速度快于LinkedList,但LinkedList的插入和删除速度快于ArrayList和Vector。 17. 有一篇英文文章 ( 也就是说每个...

    java面试宝典

    63、ArrayList和Vector的区别 16 64、Collection 和 Collections的区别 17 65、Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别 17 66、HashMap和Hashtable的区别 17 ...

    java面试笔试资料包括JAVA基础核心知识点深度学习Spring面试题等资料合集.zip

    第四题 ArrayList LinkedList Vector的区别.pdf docker讲得最清楚.doc Dubbo是什么?能做什么?.doc java 基于TCP协议的Socket编程和通信.doc Java面试高级篇—说说TCP,UDP和socket,Http之间联系和区别.doc MySQL...

    最新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面试宝典2012版.pdf

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

    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的区别 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面试宝典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后端技术面试汇总-2019

    - **ArrayList与Vector区别**: - **Vector**:线程安全,内部使用synchronized关键字。 - **ArrayList**:非线程安全,性能更高。 - **HashMap和Hashtable的区别**: - **Hashtable**:线程安全,不允许null键...

    java面试题

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

    超级有影响力霸气的Java面试题大全文档

     ArrayList 和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,...

Global site tag (gtag.js) - Google Analytics