美文网首页
JAVA与集合

JAVA与集合

作者: 靈08_1024 | 来源:发表于2018-05-26 09:16 被阅读1次

    JAVA的都知道的集合容器。

    关于集合,先上一张脑图吧。。


    image.png

    本篇源自于本人以前的《JAVA安全与并发》一文。因其文太长,所以剔出。

    容器

    同步容器

    在List中ArrayList对应的同步类为Vector(不一定安全),在Map中HashMap对应的安全类为HashTable,其底层原理是所有的方法都是synchronized。
    Collections.synchronizedXXX(List、Set、Map)等使线程安全的,其底层所有方法是synchronized该对象来实现的。效率太低,而且在使用时要注意多线程操作不同方法的并发影响。不建议使用。

    注意:Vector、HashTable只是同步,而不一定线程安全!!!
    如两个线程,一个访问remove,一个访问get,因为他是针对于方法级的,只是同一时间段只能有一个线程执行该方法。
    
    HashTable继承Dictionary,HashMap继承自AbstractMap。
    HashMap可以存null,HashTable不可以。
    

    以下类基本都来自于J.U.C,即java.util.concurrent包。

    并发容器

    并发容器。
    CopyOnWriteArrayList
    采用新开辟空间,然后复制数组,加上锁,执行添加操作来执行的。读没有锁。
    使用场景:读多写少。
    特点:

    1. 线程安全,适合并发;
    2. 实时性差;
    3. 内存开销大;
    4. Iterator不支持任何可变操作(add,set,remove)。

    CopyOnWriteArraySet
    底层为CopyOnWriteArrayList。其特点等参考CopyOnWriteArrayList。
    Iterator不支持remove操作。
    ConcurrentSkipListSet
    TreeSet的线程安全版。底层采用ConcurrentSkipListMap来实现。
    特点:

    1. 支持自然排序;
    2. 无法使用null;
    3. 多线程操作add、remove等都是线程安全的;

    注意:批量操作时,如addAll、removeAll等都不一定能保证原子性,因为其底层也是执行add等方法,只能保证每单次执行是线程安全的。

    ConcurrentHashMap
    HashMap的线程安全版。
    适用场景:
    特点:

    1. 不允许null;
    2. 线程安全(见下面)。

    ConcurrentSkipListMap
    TreeMap的线程安全版。底层采用SkipList(跳表)来实现。
    适用场景:用户数据量越大,优势越明显。
    特点:

    1. 存取时间和数据量无关;(数据量越大越有优势)
    2. 有序;
    3. 安全。
    HashMap和ConcurrentHashMap的比较
    在JDK8中,HashMap的数据结构为数组+链表/红黑树(大于8的节点时)。其resize中,关于元素的分布,没有像之前那样rehash,而是通过计算“此节点的hash和原容量”的位运算,为0,保持原位,否则分配到“原索引+原容量”位置。(一说是看位运算的高分位)
    
    在JDK8之前,ConcurrentHashMap对bucketIndex进行了分段(Segment),且在分段上有锁的保护。在锁期间,别的线程可以对其他分段进行处理。
    
    在JDK8中,ConcurrentHashMap取消了之前的分段锁,而是采用CAS+synchronized来进行处理。
    

    JDK8之ConcurrentHashMap插入实现原理
    采用Unsafe.getObjectVolatile来直接从主内存中获取(保证取新),若为空,说明该位置第一次插入,用CAS插入即可。
    若不为空,则synchronized该对象,再次执行Unsafe.getObjectVolatile保证取新,若变了重头再来。
    若未变,判断该对象的hash是否大于0,是,则找该节点,有则替换值,无则指定到next上。
    若否,判断是否为树节点,是,则插入到树中。
    其他情况不处理。
    若达到要求,则树化节点。
    最后扩容,采用CAS来执行。保证数组长度为2倍,容量为1.5倍。
    参考:深入浅出ConcurrentHashMap1.8
    HashMap的扩容机制---resize()

    相关文章

      网友评论

          本文标题:JAVA与集合

          本文链接:https://www.haomeiwen.com/subject/nggpjftx.html