zoukankan      html  css  js  c++  java
  • 多线程下的集合类实现和原理

    多线程下,在单线程下使用的HashMap 和ArrayList 就会出现一定的问题,他们并不能支持多并发,但是sun也提供了下面两种多线程结合,这是多线程下常用的集合,重点讲述这两个集合。

    1、ConcurrentHashMap

    (1) 对HashTable来说,每个方法上都加上了synchronized 保证线程安全,但是缺点是锁了整个链表,使效率低,所以出现了hashMap,但是在多线程下hashMap在扩充entry的时候又会出现链表成环状,使get方法得到一个环形,从而使方法出现死循环,线程导致cpu100%,多线程通过collections.synchronizedMap得到的hashMap是线程安全, 这其实是让hashMap的方法加上synchronized其实和hashTable也就差不多了,但是对ConcurrentHashMap来说,允许多个修改操作并发进行,其关键在于使用了锁分离技术。
    它使用了多个锁来控制对hash表的不同部分进行的修改。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的hashTable,
    它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。
    有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,
    又按顺序释放所有段的锁。这里“按顺序”是很重要的,否则极有可能出现死锁,在ConcurrentHashMap内部,段数组是final的,
    并且其成员变量实际上也是final的,但是,仅仅是将数组声明为final的并不保证数组成员也是final的,这需要实现上的保证。
    这可以确保不会出现死锁,因为获得锁的顺序是固定的
    (2) ConcurrentHashMap和Hashtable主要区别就是围绕着锁的粒度以及如何锁,可以简单理解成把一个大的HashTable分解成多个,形成了锁分离。

     

     

    2、CopyOnWriteArrayList

      ArrayList不安全的原因是 添加元素的时候分两步。

        1. 在 Items[Size] 的位置存放此元素; 
        2. 增大 Size 的值。 

     A线程往下标为0添加元素,CPU调度的时候切换到也往下标为0添加元素,然后两个线程执行完成,arraylist只有一个元素,而size的值是2。
    (1)什么是CopyOnWrite容器
     CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,
      复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,
      因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。
     (2)CopyOnWriteArrayList的实现原理
     在使用CopyOnWriteArrayList之前,我们先阅读其源码了解下它是如何实现的。以下代码是向CopyOnWriteArrayList中add方法的实现
     (向CopyOnWriteArrayList里添加元素),可以发现在添加的时候是需要加锁的,否则多线程写的时候会Copy出N个副本出来。

     (3)读的时候不需要加锁,如果读的时候有多个线程正在向CopyOnWriteArrayList添加数据,读还是会读到旧的数据,因为写的时候不会锁住旧的CopyOnWriteArrayList。

     (4)内存占用问题。因为CopyOnWrite的写时复制机制,所以在进行写操作的时候,内存里会同时驻扎两个对象的内存,旧的对象和新写入的对象(注意:在复制的时候只是复制容器里的引用,只是在写的时候会创建新对象添加到新容器里,而旧容器的对象还在使用,所以有两份对象内存)。如果这些对象占用的内存比较大,比如说200M左右,那么再写入100M数据进去,内存就会占用300M,那么这个时候很有可能造成频繁的Yong GC和Full GC。之前我们系统中使用了一个服务由于每晚使用CopyOnWrite机制更新大对象,造成了每晚15秒的Full GC,应用响应时间也随之变长。

      针对内存占用问题,可以通过压缩容器中的元素的方法来减少大对象的内存消耗,比如,如果元素全是10进制的数字,可以考虑把它压缩成36进制或64进制。或者不使用CopyOnWrite容器,而使用其他的并发容器,如ConcurrentHashMap

      (5)数据一致性问题。CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性。所以如果你希望写入的的数据,马上能读到,请不要使用CopyOnWrite容器。

  • 相关阅读:
    SharePoint 2013 安装.NET Framework 3.5 报错
    SharePoint 2016 配置工作流环境
    SharePoint 2016 站点注册工作流服务报错
    Work Management Service application in SharePoint 2016
    SharePoint 2016 安装 Cumulative Update for Service Bus 1.0 (KB2799752)报错
    SharePoint 2016 工作流报错“没有适用于此应用程序的地址”
    SharePoint 2016 工作流报错“未安装应用程序管理共享服务代理”
    SharePoint JavaScript API in application pages
    SharePoint 2016 每天预热脚本介绍
    SharePoint 无法删除搜索服务应用程序
  • 原文地址:https://www.cnblogs.com/Seeasunnyday/p/6487090.html
Copyright © 2011-2022 走看看