Java并发(十七):ConcurrentHashMap

先做总结: 1、HashMap HashTable ConcurrentHashMap

HashMap:线程不安全

HashTable:线程安全,每个方法都加了 synchronized 修饰。类似 Collections.synchronizedMap(hashMap)

       对读写加锁,独占式,一个线程在读时其他线程必须等待,吞吐量较低,性能较为低下。

ConcurrentHashMap:利用CAS+Synchronized来保证并发的安全性。数据结构同HashMap。

2、ConcurrentHashMap如何实现线程安全?

(1)get()方法使用tabAt(Node<K, V>[], int)方法

    调用Unsafe的native方法 getObjectVolatile(Object obj, long offset);

    // 获取obj对象中offset偏移地址对应的object型field的值,支持volatile load语义,即:让缓存中的数据失效,重新从主内存加载数据

(2)put()方法

  ①需要获取数组上的Node时同样使用tabAt()方法

  ②设置数组上Node是使用casTabAt() 方法,

    casTabAt()调用Unsafe的native方法compareAndSwapObject(),CAS操作

  ③哈希冲突之后,需要操作改hash值对应的链表/红黑树,此时synchronized(该链表第一个Node)

    保证线程安全的基础上,减小了锁的粒度。

一、属性

// 最大容量:2^30=1073741824 private static final int MAXIMUM_CAPACITY = 1 << 30; // 默认初始值,必须是2的幕数 private static final int DEFAULT_CAPACITY = 16; // static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // private static final int DEFAULT_CONCURRENCY_LEVEL = 16; // private static final float LOAD_FACTOR = 0.75f; // 链表转红黑树阀值,> 8 链表转换为红黑树 static final int TREEIFY_THRESHOLD = 8; //树转链表阀值,小于等于6(tranfer时,lc、hc=0两个计数器分别++记录原bin、新binTreeNode数量,<=UNTREEIFY_THRESHOLD 则untreeify(lo)) static final int UNTREEIFY_THRESHOLD = 6; // static final int MIN_TREEIFY_CAPACITY = 64; // private static final int MIN_TRANSFER_STRIDE = 16; // private static int RESIZE_STAMP_BITS = 16; // 2^15-1,help resize的最大线程数 private static final int MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1; // 32-16=16,sizeCtl中记录size大小的偏移量 private static final int RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS; // forwarding nodes的hash值 static final int MOVED = -1; // 树根节点的hash值 static final int TREEBIN = -2; // ReservationNode的hash值 static final int RESERVED = -3; // 可用处理器数量 static final int NCPU = Runtime.getRuntime().availableProcessors();

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzdxsp.html