JUC&安全/非安全容器

一、JUC

java.util.concurrent下的类就叫JUC类,JUC下典型的类有:
1.ReentrantLock可重入锁
2.Semaphore信号量
3.CountDownLatch计数器
4.CyclicBarrier循环屏障

二、线程安全&非安全容器

2.1非线性安全容器

在这里插入图片描述

2.2线性安全容器

在这里插入图片描述

三、关于HashMap

hashMap是不安全的,体现如下:

  1. 在jdk1.7中,多线程环境下,扩容时因为采用头插法会造成环形链或数据丢失。
  2. 在jdk1,8中,多线程环境下,会发生数据覆盖问题

3.1hash JDK1.7死循环

jdk1.7中hashMap是由数组+链表组成
在这里插入图片描述
jdk1.8中hashMap是由数组+红黑树组成
链表升级为红黑树的要求:
当链表长度>8并且数组长度>64时,才会升级为红黑树。
在这里插入图片描述
正常情况下的扩容:
旧hashMap的节点会依次转移到新hashMap中,旧hashMap转移的顺序是A ,B ,C而新hashMap使用的是头插法,所以最终在新hashMap中的顺序是C, B, A如下图所示:
在这里插入图片描述
死循环是因为并发hashMap扩容导致的,并发扩容第一步,线程T1和线程T2要对hashMap进行扩容操作,此时T1和T2指向的是链表的头节点元素A,而T1和T2的下一个节点也就是T1.next和T2.next指向的是B节点,如下图:
在这里插入图片描述
死循环的第二部操作是,线程T2时间片用完进入休眠状态,而线程T1开始执行扩容操作,一直到线程T1扩容完成后,线程T2才被唤醒,扩容之后的场景如下图:
在这里插入图片描述
在这里插入图片描述
从上图可知线程T1执行之后,因为是头插法,所以HashMap的顺序已经发生了变化,但线程T2对于发生的一切是不可知的,所以它的指向元素依然没变,T2指向的是A元素,T2.next指向的节点是B元素。

3.2线程安全的字典

HashMap本身是不安全的,在多线程环境下可以使用哈希表可以使用Hashtable 和 ConcurrentHashMap

3.2.1Hashtable

Hashtable只是简单的把关键方法加上了 synchronized 关键字,这相当于直接对Hashtable对象本身加锁,但这样效率很低。

3.2.2ConcurrentHashMap

ConcurrentHashMap在不同的JDK中实现是不一样的。
在 JDK 1.7 中它使用的是数组加链表的形式实现的,而数组⼜分为:大数组 Segment 和小数组 HashEntry
在这里插入图片描述
ConcurrentHashMap 的线程安全是建立在 Segment 加锁的基础上的,所以我们把它称之为分段锁或片段锁,如下图:
在这里插入图片描述
在 JDK 1.7 中,ConcurrentHashMap 虽然是线程安全的,但因为它的底层实现是数组 + 链表的形式,所以在数据比较多的情况下访问是很慢的,因为要遍历整个链表,⽽ JDK 1.8 则使用了数组 + 链表/红黑树的方式优化了 ConcurrentHashMap 的实现。
在 JDK 1.8 中我们可以简单的认为,ConcurrentHashMap 是在头节点加锁来保证线程安全的,锁的粒度相比 Segment 来说更小了,发生冲突和加锁的频率降低了,并发操作的性能就提高了,具体如下图:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值