和 存入 Queue 取出 是线程安全的吗? (存入和存出)
本文目录导航:
Queue 存入 和 取出 是线程安全的吗?
Queue本身并不是线程安全的, 有两种方法来保证线程安全:1. 手动加锁。Queue myCollection = new Queue();lock(){foreach (object item in myCollection){// Insert your code here.}}2. 调用Synchronized方法,这时候得到的就是一个线程安全的Queue Queue mySyncdQ = ( myQ );

ConcurrentHashMap
HashMap是我们用得非常频繁的一个集合,但是它是线程不安全的。
并且在多线程环境下,put操作是有可能产生死循环,不过在JDK1.8的版本中更换了数据插入的顺序,已经解决了这个问题。
为了解决该问题,提供了Hashtable和(hashMap)两种解决方案,但是这两种方案都是对读写加锁,独占式。
一个线程在读时其他线程必须等待,吞吐量较低,性能较为低下。
而J.U.C给我们提供了高性能的线程安全HashMap:ConcurrentHashMap。
在1.8版本以前,ConcurrentHashMap采用分段锁的概念,使锁更加细化,但是1.8已经改变了这种思路,而是利用CAS+Synchronized来保证并发更新的安全,当然底层采用数组+链表+红黑树的存储结构。
HashMap 是最简单的,它不支持并发操作,下面这张图是 HashMap 的结构:
HashMap 里面是一个数组,然后数组中每个元素是一个单向链表。
每个绿色的实体是嵌套类 Entry 的实例,Entry 包含四个属性:key, value, hash 值和用于单向链表的 next。
public HashMap(int initialCapacity, float loadFactor) 初始化方法的参数说明:
put 过程
get过程
ConcurrentHashMap 和 HashMap 思路是差不多的,但是因为它支持并发操作,所以要复杂一些。
整个 ConcurrentHashMap 由一个个 Segment 组成,Segment 代表”部分“或”一段“的意思,所以很多人都会将其描述为分段锁。
简单的说,ConcurrentHashMap 是一个 Segment 数组,Segment 通过继承 ReentrantLock 来进行加锁,所以每次需要加锁的操作锁住的是一个 segment,这样只要保证每个 Segment 是线程安全的。
再具体到每个 Segment 内部,其实每个 Segment 很像之前介绍的 HashMap,每次操作锁住的是一个 segment,这样只要保证每个 Segment 是线程安全的。
初始化
public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) 初始化方法
举个简单的例子:
用 new ConcurrentHashMap() 无参构造函数进行初始化的,那么初始化完成后:
put过程
get过程
Java8 对 HashMap 进行了一些修改,最大的不同就是利用了红黑树,所以其由 数组+链表+红黑树 组成。
根据 Java7 HashMap 的介绍,我们知道,查找的时候,根据 hash 值我们能够快速定位到数组的具体下标,但是之后的话,需要顺着链表一个个比较下去才能找到我们需要的,时间复杂度取决于链表的长度。
为了降低这部分的开销,在 Java8 中,当链表中的元素超过了 8 个以后,会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度。
jdk7 中使用 Entry 来代表每个 HashMap 中的数据节点,jdk8 中使用 Node,基本没有区别,都是 key,value,hash 和 next 这四个属性,不过,Node 只能用于链表的情况,红黑树的情况需要使用 TreeNode。
我们根据数组元素中,第一个节点数据类型是 Node 还是 TreeNode 来判断该位置下是链表还是红黑树的。
put过程
和jdk7的put差不多
get 过程分析
Java7 中实现的 ConcurrentHashMap 还是比较复杂的,Java8 对 ConcurrentHashMap 进行了比较大的改动。
可以参考 Java8 中 HashMap 相对于 Java7 HashMap 的改动,对于 ConcurrentHashMap,Java8 也引入了红黑树。
在1.8版本以前,ConcurrentHashMap采用分段锁的概念,使锁更加细化,但是1.8已经改变了这种思路,而是利用CAS+Synchronized来保证并发更新的安全,底层采用数组+链表+红黑树的存储结构。
ConcurrentHashMap通常只被看做并发效率更高的Map,用来替换其他线程安全的Map容器,比如Hashtable和。
线程安全的容器,特别是Map,很多情况下一个业务中涉及容器的操作有多个,即复合操作,而在并发执行时,线程安全的容器只能保证自身的数据不被破坏,和数据在多个线程间是可见的,但无法保证业务的行为是否正确。
ConcurrentHashMap总结:
案例2:业务操作的线程安全不能保证
案例3:多线程删除
12.7 对比Hashtable Hashtable和ConcurrentHashMap的不同点:
Hashtable对get,put,remove都使用了同步操作,它的同步级别是正对Hashtable来进行同步的,也就是说如果有线程正在遍历集合,其他的线程就暂时不能使用该集合了,这样无疑就很容易对性能和吞吐量造成影响,从而形成单点。
而ConcurrentHashMap则不同,它只对put,remove操作使用了同步操作,get操作并不影响。
Hashtable在遍历的时候,如果其他线程,包括本线程对Hashtable进行了put,remove等更新操作的话,就会抛出ConcurrentModificationException异常,但如果使用ConcurrentHashMap的话,就不用考虑这方面的问题了
c的map线程安全么
c的map线程不安全。
map在并发情况下,只读是线程安全的,同时读写是线程不安全的。