zoukankan      html  css  js  c++  java
  • java 数据集合类

    map相关类和其他集合类(List,Set等)的接口并不一致。map类继承自Map接口,而其他集合类继承自Collection接口,Collection接口继承自Iterable接口。凡是被Iterable接口修饰的类都是可以得到对应Iterator接口实现迭代遍历的。

    遍历map

    在java8之前,map类(比如hashmap)并不能实现自己的遍历,只能通过转化为Set<Entry>,Set<key>,Set<value>进行遍历。java新增了foreach的迭代方法,可以不用再转为set对象进行迭代了

            HashMap<String, String> hashMap = new HashMap<>();
            //方法一
            hashMap.forEach((key, value) -> {});
            //方法二
            for (Entry<String, String> entry : hashMap.entrySet()) {
                
            }
            //方法三,遍历key,再通过key得到对应键值
            for(String key : hashMap.keySet()) {
                
            }
            //方法四,直接遍历value
            for(String value : hashMap.values()) {
                
            }

    遍历时修改集合

    Collection接口的集合类在遍历的时候并不能进行删除和添加操作,否则就会报ConcurrentModificationException的异常,例如进行下面的遍历操作都会报错

            ArrayList<String> list = new ArrayList<>();
            list.add("ele1");
            list.add("ele2");
            list.add("ele3");
            list.add("ele4");
            list.add("ele5");
            list.add("ele6");
            //遍历一报错
            list.forEach(ele -> list.remove(ele));
            //遍历二报错
            for (String entry : list) {
                list.remove(entry);
            }
            //遍历三报错
            Iterator<String> ite = list.iterator();
            while (ite.hasNext()) {
                String value = ite.next();
                list.remove(value);
            }
            //遍历四不会报错,调用迭代器的删除方法
            Iterator<String> iter = list.iterator();
            while (iter.hasNext()) {
                String value = iter.next();
                iter.remove();
            }

    因此要修改还必须依赖迭代器的删除方法。

    关于产生ConcurrentModificationException报错的原因,请查看下面的文章分析:

    https://www.cnblogs.com/zhuyeshen/p/10956822.html

    https://blog.csdn.net/tttzzztttzzz/article/details/87556048

    HashMap实现

    初始化

    hashmap时lazy-load方式,执行构造函数时只会设置初始容量和负载系数。

    负载系统默认是0.75,这是查找和插入操作的最佳平衡点,如果过高,则容易发生hash冲突,造成同一hash值对应的链表长度过长,影响查找效率;如果过低,则会造成hash过于稀疏,浪费空间。

    插入操作

    hashmap是在插入第一个元素时确定容量和分配空间的,初始容量并不是真实的容量,容量都是略大于初始容量的二的幂次方。这是为了减少hash冲突,这里就要说一下hashmap的hash算法。先得到key值对应的hash值,然后将hash值左移16位,然后再与容量-1进行位的异或操作.

    将hash值左移16位是因为hash的低16位更容易发生hash冲突,所以要利用高16位,而容量-1对应的每个二进制位都是1。这样在计算hash值时,能够最大限度的减少hash冲突。

    数据结构

    主体是数组类型,元素类型是key-value的Node类型链表。hash冲突的元素都会被放置到同一个链表中,但是如果链表长度过长就会影响查找效率,因此在Java1.8中,如果链表长度大于8,就自动将链表转化为红黑树。转化为红黑树后,插入操作会有影响,涉及到树的平衡操作。

    resize操作

    hashmap内部有一个门限值,其值为容量乘以负载系数。当hashmap的长度超过门限值时就会执行resize。resize的长度是将当前数组的长度扩大两倍,然后每个元素重新计算hash值确定新的位置,但因为是位操作,所以新的索引位置是由原来key的有效hash值左移一位决定的。如果该位值是0,则在新数组中的索引位置不变;如果是1,则新的索引位置是原索引加上原数组长度。

    Java1.8之前,多线程下对线程进行扩容的时候会造成链表的循环引用问题,造成死循环,这是因为在链表中添加新元素的时候,总是把它加在链表头部。在1.8中就改成了链表尾部,既避免了循环应用,也因为要检查链表的长度,当长度超过8时,会将链表转化为一个红黑树。但是hashmap在1.8下的多线程下还是有很多别的问题,避免使用。

    ConcurrentHashMap实现

    Java1.7

    put加锁
    通过分段加锁segment,一个hashmap里有若干个segment,每个segment里有若干个桶,桶里存放K-V形式的链表,put数据时通过key哈希得到该元素要添加到的segment,然后对segment进行加锁,然后在哈希,计算得到给元素要添加到的桶,然后遍历桶中的链表,替换或新增节点到桶中
    size
    分段计算两次,两次结果相同则返回,否则对所以段加锁重新计算

    Java1.8

    put

    CAS 加锁
    1.8中不依赖与segment加锁,segment数量与桶数量一致;
    首先判断容器是否为空,为空则进行初始化利用volatile的sizeCtl作为互斥手段,如果发现竞争性的初始化,就暂停在那里,等待条件恢复,否则利用CAS设置排他标志(U.compareAndSwapInt(this, SIZECTL, sc, -1));否则重试
    对key hash计算得到该key存放的桶位置,判断该桶是否为空,为空则利用CAS设置新节点
    否则使用synchronize加锁,遍历桶中数据,替换或新增加点到桶中
    最后判断是否需要转为红黑树,转换之前判断是否需要扩容

    size
    利用LongAdd累加计算

    上面的集合对象都不支持在直接遍历元素时,进行添加和删除操作,但是ConcurrentHashMap可以在遍历时进行更新操作。但并不能保证实时更新,本次遍历添加的元素可能不会在本次遍历出来,只能在下次才能遍历出来。详细说明如下:

    https://www.cnblogs.com/williamjie/p/9099861.html

    https://www.jianshu.com/p/d10256f0ebea

    https://www.cnblogs.com/zhuawang/p/4779649.html

    https://www.cnblogs.com/heqiyoujing/p/10928423.html

    https://blog.csdn.net/killalllsd/article/details/83607945

  • 相关阅读:
    mysql对库,表,数据类型的操作以及完整性约束
    mysql数据库初步了解
    响应式及Bootstrap
    事件流丶事件对象
    JQuery初识(三 )
    JQuery初识(二)
    JQuery初识
    sencha touch tpl 实现按钮功能
    sencha touch 分享到微博扩展
    sencha touch 隐藏滚动条样式的几种方式
  • 原文地址:https://www.cnblogs.com/suntp/p/12097965.html
Copyright © 2011-2022 走看看