ConcurrentHashMap

HashTable线程安全,效率非常低,锁的资源竞争

 

多线程共享同一个HashTable   HashTable加锁了,影响效率。每次只能有一个线程去操作 put 和 get 只能有一个线程可以操作。

 

jdk5之后,引入了CurrentHashMap<K,V>

分段锁:

    一个整体拆分成16段。每段是一个HashTable(),默认16段。 绝对大多数用的时候不是同一把锁,但是肯定是不一定的啊。因为毕竟看你怎么查的了

  

 

注意get是没有加锁的!

  get没有加锁的话,ConcurrentHashMap是如何保证读到的数据不是脏数据的呢?

  volatile登场!

  【对于可见性,Java提供了volatile关键字来保证可见性、有序性。但不保证原子性。

    普通的共享变量不能保证可见性,因为普通共享变量被修改之后,什么时候被写入主存是不确定的,当其他线程去读取时,此时内存中可能还是原来的旧值,因此无法保证可见性。

    • volatile关键字对于基本类型的修改可以在随后对多个线程的读保持一致,但是对于引用类型如数组,实体bean,仅仅保证引用的可见性,但并不保证引用内容的可见性。。
    • 禁止进行指令重排序。

   】

总结:

  • 第一:使用volatile关键字会强制将修改的值立即写入主存;
  • 第二:使用volatile关键字的话,当线程2进行修改时,会导致线程1的工作内存中缓存变量的缓存行无效(反映到硬件层的话,就是CPU的L1或者L2缓存中对应的缓存行无效);
  • 第三:由于线程1的工作内存中缓存变量的缓存行无效,所以线程1再次读取变量的值时会去主存读取。

    

   

volatile修饰数组对get操作没有效果那加在数组上的volatile的目的是什么呢?

其实就是为了使得Node数组在扩容的时候对其他线程具有可见性而加的volatile

 

总结

  • 在1.8中ConcurrentHashMap的get操作全程不需要加锁,这也是它比其他并发集合比如hashtable、用Collections.synchronizedMap()包装的hashmap;安全效率高的原因之一。
  • get操作全程不需要加锁是因为Node的成员val是用volatile修饰的和数组用volatile修饰没有关系。
  • 数组用volatile修饰主要是保证在数组扩容的时候保证可见性。

 

 

 

 

 

 

 

    

 

posted @ 2019-02-05 02:19  toov5  阅读(207)  评论(0编辑  收藏  举报