并发容器

位运算符实际开发用途场景

        可以用于权限和商品的情景

hashMap在1.7中会造成死循环原因

        hashMap在jdk1.7的版本使用时,如果是两个线程向map里put数据时会产生环形的数据结构,造成死循环,导致cpu利用率变为100%。产生环形数据结构原因:当两个线程并发的进行扩容时,一个线程完成了全部的扩容操作,而另一个线程执行过程中被挂起了,而这个挂起的线程被恢复执行以后,在自己的newtable里进行一次扩容操作,在进行头插法的链表操作,会造成两个元素之间next指针相互指着,形成一种循环链表而导致一个死循环(这只是一个简要说明,如果想彻底明白的话需要根据老师的笔记自己在纸上画图理解)。

hashMap的一次扩容过程

        1、取当前table的2倍作为新table的大小;

        2、根据算出的新table的大小new出一个新的Entry数组来,名为newTable;

        3、轮询原table的每一个位置,将每一个位置上连接的Entry,算出在新的table上的位置,并以链表形式连接

        4、原table上的所有Entry全部轮询完毕之后,意味着原table上面的所有Entry已经移到新的table上,hashmap中的table指向newTable。

hashMap插入数据方式

        hashMap向链表中插入元素时使用头插法插入元素的。

concurrentHashMap

      jdk1.7中

         数据结构:首先有一个segment的数组(初始化后不可扩容),每一个segment下有一个table数组,是一个链表,数据结构为HashEntry。segment具有可重入锁,由于有锁的机制,可以保护每一个segment下挂载的HashEntry。初始化缺省的并发度的值为16(也就是segment的数组长度)。初始化时只会创建segment[0]的tabel,其余的会在put时初始化。同时值都需要符合2的n次方。

         get方法为什么不需要加锁:因为hashEntry定义结构时,使用了volatile以及final关键字,保证拿到的值都是最新的。

        put方法:先计算key的hash找到segment的对应的数组,然后使用CAS初始化segment,然后进入到HashEntry对象里,循环当前链表,如果没找到这个key,使用头插法把当前插入到链表中,如果找到了,那就替换掉原来的key的对象。

        高并发时不建议的操作:高并发时不推荐使用size()和containsValue()方法,因为会把所有的segment加锁,比较重。

     jdk1.8中

        数据结构:采用数组加链表加红黑树。取消了1.7中的segment,而1.7中segment下的hashEntry被Node取代了。当链表过长时(超过8)就会从链表转为红黑树,当红黑树节点的个数小于6的时候会从红黑树变为链表。Node中的数据结构也是用final和volatile修饰的。1.8中的conCurrentHashMap中的TreeNode继承的是Node,而hashMap继承的是LinkedHashMap.Entry。

        初始化以及插入数据方式:初始化时,只是给sizeCtl附了一个值,其他的什么都没做。向Node中插入元素用的是尾插法。

        put流程:首先根据key计算hash值,然后检查table上是否有元素,没有元素则直接放到这个table数组上面,如有的话就拿到节点的树,根据节点下挂载的是红黑树还是链表,按照两种数据结构进行插入,插入完成后,判定是否要将链表转成红黑树,然后判定是否要在进行一次扩容的操作。

        remove流程:和put类似,只是插入换成移除,如果是红黑树则转成链表。

ConCurrentSkipListMap与ConCurrentSkipListSet

        两个存的都是有序的map和set.ConCurrentSkipListSet内部实现其实就是对ConCurrentSkipListMap的一个包装而已,同理,TreeSet也是对TreeMap的一个包装。两个是线程安全的。

ConcurrentLinkedQueue

        ConcurrentLinkedQueue是LinkedList的并发版本。Add()是插入元素,offer()是获取元素,peek是检索元素但是并不移除元素,poll是移除元素。

CopyOnWriteArrayList和CopyOnWriteArraySet

        CopyOnWriteArrayList和CopyOnWriteArraySet是写时复制容器。才用了读写分离的思想。用于场景:大部分是读,偶尔有写的现象。比如白名单黑名单。缺点是性能很低,内存开销大,数据一致性差。

阻塞队列

    所有的阻塞队列:
    1、ArrayBlockingQueue:一个由数组组成的有界阻塞队列

    2、LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列

    3、PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。

    4、DelayQueue:一个使用优先级队列实现的无界阻塞队列。

    5、SynchronousQueue:一个不存储元素的阻塞队列。

    6、LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。

    7、LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。

    原理:采用等待通知模式。

    ArrayBlockingQueue与LinkedBlockingQueue:

    ArrayBlockingQueue和LinkedBlockingQueue除了数据结构不同,在实现上ArrayBlockingQueue用的是一把锁,而LinkedBlockingQueue用的是两把锁,生产者一把锁,消费者一把锁。

    


相关知识点问答记录

问:hashMap和hashTable有什么区别?

答:hashMap线程不安全,hashTable是线程安全的但是性能没有hashMap高,hashMap允许key和value为null,而hashTable不允许。hashMap初始化为16,hashTable初始化为11.扩容时hashMap为2倍,而hashTable为2倍+1。hashMap在hash值散列的时候会重新计算hash,而hashTable会直接使用hashCode值。

问:Java中的另一个线程安全的与HashMap极其类似的类是什么,同样是线程安全,它与HashTable在线程实现上有什么不同?

答:是conCurrentHashMap。hashTable实现上使用了synchronize关键字,锁的是整个的map,高并发下竞争越激烈,效率越低,而conCurrentHashMaphashMap在1.7中采用分段锁的方式,1.8中采用CAS加Synchronize加分段锁,大大提升了效率。

问:HashMap和conCurrentHashMap区别?

答:一个是线程不安全,一个是线程安全。HashMap允许键值对为null,而conCurrentHashMap不允许。

问:为什么conCurrentHashMap比hashTable效率要高?

答:因为hashTable用了一把锁,锁住了整个的map,多个线程竞争一把锁容易阻塞。而conCurrentHashMap采用了分段锁,这样锁的力度就降低了。

问:conCurrentHashMap锁机制具体分析(jdk1.7 vs jdk1.8)?

答:1.7里采用了分段锁机制实现了并发的更新操作,而底层采用了数组加链表的结构,数组是segment,链表是hashEntry,segment继承可重入锁来充当了锁的角色,由每个segment保护自己下面所属的数据,hashEntry组成了链表被每个segmeng保护。而1.8采用了node+cas+syn关键字来保证并发安全,取消了segment这一层,同时加入了红黑树机制,红黑树加链表的相互转换能提升性能。

问:conCurrentHashMap在jdk1.8中,为什么要使用内置锁synchronize来代替重入锁ReenTrantLock?

答:第一,开发团队在1.8中对syn关键字做了大量性能优化,而且基于虚拟机本身的优化空间更大,更加自然。第二,显示锁是一个类,意味着显示锁是一个对象需要消耗内存的,而syn的内存的开销更小。

问:1.8下conCurrentHashMap简单介绍?

答:在conCurrentHashMap里有一个比较重要的成员变量,sizeCtl。它控制了初始化的大小以及扩容的大小以及当前conCurrentHashMap是否进行初始化以及是否正在进行扩容。第二,重要的数据结构,Node。继承至Entry,用于存储数据,是存储的基本单元。同时基于Node的基础上,支持红黑树又扩展了TreeNode和TreeBin。TreeNode用于在红黑树上存储数据,而TreeBin封装了TreeNode,还提供了属性值。第三,get时计算hash值,如果定位到了table则直接返回,如果不是则根据当前节点的类型,分别按照链表和红黑树的方式查找当前元素所在的位置。如果进行put时,如果没有进行初始化,那么进行初始化,如果没有hash冲突,则使用cas操作进行插入数据,否则对当前table的元素进行加锁,如果是链表插入则按照尾插法进行插入,如果是红黑树则按照红黑树的方式插入,插入后如果链表长度大于8则转成红黑树。插入后如果需要扩容则再扩容。扩容方法:为了提高效率,工作线程会帮助进行一起进行并发的扩容,效率会很高,为了避免扩容时多个线程对节点的一个冲突,每个线程会用一个步长的形式进行节点的扩容操作。

问:conCurrentHashMap的并发度是什么?

答:1.7为16,1.8 中并发度则无太大的实际意义了,主要用处就是当设置的初始容量小于并发度,将初始容量提升至并发度大小。

CopyOnWriteArrayList和CopyOnWriteArraySet是写时复制容器。才用了读写分离的思想。用于场景:大部分是读,偶尔有写的现象。比如白名单黑名单。缺点是性能很低,内存开销大,数据一致性差

采用等待通知模式

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342