zoukankan      html  css  js  c++  java
  • java并发-ConcurrentMap

    java并发-ConcurrentMap

    标签: java 并发

    背景描述:

    最近在深入学习Java并发,看了几篇不错的文章,记个笔记

    1.HashMap

    (1)采用哈希表,使用数组+链表的形式进行存储。由于hash()方法可能产生哈希碰撞且会被重写,则使用链表存储hash碰撞的数据。
    (2)计算hashmap的初始长度时,需要计算一个2的N次幂大于等于指定数值,后续扩容都是2倍。hashmap中经常用到与运算计算hash值(提高效率)。当数组的长度为2的n次方时,存储数据的数组的length必为偶数,length-1必为奇数,而奇数的二进制最后一位必为1,则hash值与奇数与运算时既有可能得到奇数,也有可能得到偶数;反之,如果length为奇数,则lenth-1为偶数,其二进制最后一位为0,与任意数进行与运算最后一位都为0,永远都是偶数。相当于浪费了数组一半的空间,更容易形成hash冲突。
    

    2.ConcurrentMap

    在多线程情况下,同时A、B两个线程走到createEntry()方法中,并且这两个线程中插入的元素hash值相同,bucketIndex值也相同,那么无论A线程先执行,还是B线程先被执行,最终都会2个元素先后向链表的头部插入,导致互相覆盖,致使其中1个线程中的数据丢失。这样就造成了HashMap的线程不安全,数据的不一致;
    
    更要命的是,HashMap在多线程情况下还会出现死循环的可能,造成CPU占用率升高,导致系统卡死。
    
    • HashTable
    与HashMap不同的是,在HashTable中,所有的方法都加上了synchronized锁,用锁来实现线程的安全性。由于synchronized锁加在了HashTable的每一个方法上,所以这个锁就是HashTable本身--this。那么,可想而知HashTable的效率是如何,安全是保证了,但是效率却损失了。
    
    • java 1.7ConcurrentMap
    在JDK1.7版本中,ConcurrentHashMap的数据结构是由一个Segment数组和多个HashEntry组成,主要实现原理是实现了锁分离的思路解决了多线程的安全问题。
    Segment数组的意义就是将一个大的table分割成多个小的table来进行加锁,也就是上面的提到的锁分离技术,而每一个Segment元素存储的是HashEntry数组+链表,这个和HashMap的数据存储结构一样。
    
    • java 1.8ConcurrentMap
    DK1.8的实现已经摒弃了Segment的概念,而是直接用Node数组+链表+红黑树的数据结构来实现,并发控制使用Synchronized和CAS来操作,整个看起来就像是优化过且线程安全的HashMap,虽然在JDK1.8中还能看到Segment的数据结构,但是已经简化了属性,只是为了兼容旧版本。
    Node是ConcurrentHashMap存储结构的基本单元,继承于HashMap中的Entry,用于存储数据,Node数据结构很简单,就是一个链表,但是只允许对数据进行查找,不允许进行修改。
    
  • 相关阅读:
    WebQQ协议分析(9)——聊天(2)
    我的程序员之路(3)——学生时代(3)
    我的程序员之路(2)——学生时代(2)
    我的程序员之路(1)——学生时代(1)
    WebQQ协议分析——目录
    我的程序员之路(4)——工作半年
    WebQQ协议分析(7)——获取群信息(2)
    WebQQ协议分析(8)——聊天(1)
    VS2008编译器下ACE的配置
    WebQQ协议分析(10)——聊天(3)
  • 原文地址:https://www.cnblogs.com/cxy2016/p/12823139.html
Copyright © 2011-2022 走看看