免锁容器之CopyOnWriteArrayList、ConcurrentHashMap

来源:互联网 发布:全职高手烽火知韩txt 编辑:程序博客网 时间:2024/05/18 02:09

    像Vector 和 Hashtable 这类早期容器具有许多synchronized方法,当他们用于非多线程的应用程序时,便会导致不可接受的开销。在Java1.2中,新的容器类库是不同步的,并且Collections类提供了各种static同步的装饰方法,从而来同步不同类型的容器。尽管这是一种改进,因为它使你可以选择在你的容器中是否要使用同步,但是这种开销依旧是基于synchronized加锁机制的。Java SE5特别添加了新的容器,通过使用更灵巧的技术来消除加锁,从而提高线程安全的性能。


    这些免锁容器背后的通用策略是:对容器的修改可以与读取操作同时发生,只要读取者只能看到完成修改的结果即可。修改是在容器数据结构的某个部分的一个单独的副本(有时是整个数据结构的副本)上执行的,并且这个副本在修改过程中是不可视的。只有当修改完成时,被修改的结构才会主动地与主数据结构进行交换,之后读取者就可以看到这个修改了。(Copy on Write

 

    CopyOnWriteArrayList 中,写入将导致创建整个底层数组的副本,而原数组将保留在原地,使得复制的数据在被修改时,读取操作可以安全地执行。当修改完成时,一个原子性的操作将把新的数组换入,使得新的出去操作可以看到这个新的修改

 

    CopyOnWriteArrayList的好处之一是当多个迭代器同时遍历和修改这个列表时,不会抛出ConcurrentModificationException(在 for each 中删除元素会抛出 ConcurrentModificationException

 

    CopyOnWriteArraySet 使用 CopyOnWriteArrayList来实现其免锁行为。

 

    ConcurrentHashMap 和 ConcurrentLinkedQueue使用了类似的技术,允许并发的读取和写入,但是容器中只有部分内容而不是整个容器可以被复制和修改。然而,任何修改在完成之前,读取者仍旧不能看到它们。ConcurrentHashMap不会抛出ConcurrentModificationException异常。

 

乐观锁

    只要你主要是从免锁容器中读取,那么它就会比其synchronized对应物快许多,因为获取和释放锁的开销被省掉了。如果需要向免锁容器中执行少量写入,那么情况依旧如此。




从测试结果来看,synchronized ArrayList无论读取者和写入者的数量是多少,都具有大致相同的性能——读取者与其他读取者竞争锁的方式与写入者相同。但是CopyOnWriteArrayList在没有写入者时,速度会快许多,并且在有五个写入者时,速度依旧明显的快。看起来你应该尽量使用CopyOnWriteArrayList,对列表写入的影响并没有超过短期同步整个列表的影响。当然,你必须在你的具体应用中尝试这两种不同的方式,以了解到底哪个更好一点。



    向ConcurrentHashMap添加写入者的影响甚至还不如CopyOnWriteArrayList明显,这是因为ConcurrentHashMap使用了一种不同的技术,它可以明显地最小化写入所造成的影响。






原创粉丝点击