网站平台由什么搭建专门制作网站

当前位置: 首页 > news >正文

网站平台由什么搭建,专门制作网站,wordpress个人收款码插件,昆山建设局图审中心网站ConcurrentHashMap底层原理 ConcurrentHashMapJDK1.7底层结构线程安全底层具体实现 JDK1.8底层结构线程安全底层具体实现 总结JDK 1.7 和 JDK 1.8实现有什么不同#xff1f;ConcurrentHashMap 中的 CAS 应用 ConcurrentHashMap ConcurrentHashMap 是一种线程安全的高效Map集合… ConcurrentHashMap底层原理 ConcurrentHashMapJDK1.7底层结构线程安全底层具体实现 JDK1.8底层结构线程安全底层具体实现 总结JDK 1.7 和 JDK 1.8实现有什么不同ConcurrentHashMap 中的 CAS 应用 ConcurrentHashMap ConcurrentHashMap 是一种线程安全的高效Map集合 底层数据结构 JDK1.7底层采用分段的数组链表实现JDK1.8 采用的数据结构跟HashMap1.8的结构一样数组链表/红黑二叉树。 JDK1.7 底层结构 ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成。 Segment 数组中的每个元素包含一个 HashEntry 数组每个 HashEntry 数组属于链表结构。 线程安全底层具体实现 首先将数据分为一段一段这个“段”就是 Segment的存储然后给每一段数据配一把锁当一个线程占用锁访问其中一个段数据时其他段的数据也能被其他线程访问。 ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成。 Segment 继承了 ReentrantLock,所以 Segment 是一种可重入锁扮演锁的角色。HashEntry 用于存储键值对数据。 static class SegmentK,V extends ReentrantLock implements Serializable { }一个 ConcurrentHashMap 里包含一个 Segment 数组Segment 的个数一旦初始化就不能改变。 Segment 数组的大小默认是 16也就是说默认可以同时支持 16 个线程并发写。 Segment 的结构和 HashMap 类似是一种数组和链表结构一个 Segment 包含一个 HashEntry 数组每个 HashEntry 是一个链表结构的元素每个 Segment 守护着一个 HashEntry 数组里的元素当对 HashEntry 数组的数据进行修改时必须首先获得对应的 Segment 的锁。也就是说对同一 Segment 的并发写入会被阻塞不同 Segment 的写入是可以并发执行的。 JDK1.8 底层结构 JDK1.8 的 ConcurrentHashMap 不再是 Segment 数组 HashEntry 数组 链表而是 Node 数组 链表 / 红黑树。不过Node 只能用于链表的情况红黑树的情况需要使用 TreeNode。当冲突链表达到一定长度时链表会转换成红黑树。 线程安全底层具体实现 ConcurrentHashMap 取消了 Segment 分段锁采用 Node CAS synchronized 来保证并发安全。数据结构跟 HashMap 1.8 的结构类似数组链表/红黑二叉树。Java 8 在链表长度超过一定阈值8时将链表寻址时间复杂度为 O(N)转换为红黑树寻址时间复杂度为 O(log(N))。 Java 8 中锁粒度更细synchronized 只锁定当前链表或红黑二叉树的首节点这样只要 hash 不冲突就不会产生并发就不会影响其他 Node 的读写效率大幅提升。 底层源码 public V put(K key, V value) {return putVal(key, value, false); }/** Implementation for put and putIfAbsent */ final V putVal(K key, V value, boolean onlyIfAbsent) {// key 和 value 不能为空if (key null || value null) throw new NullPointerException();int hash spread(key.hashCode());int binCount 0;for (NodeK,V[] tab table;;) {// f 目标位置元素NodeK,V f; int n, i, fh;// fh 后面存放目标位置的元素 hash 值if (tab null || (n tab.length) 0)// 数组桶为空初始化数组桶自旋CAS)tab initTable();else if ((f tabAt(tab, i (n - 1) hash)) null) {// 桶内为空CAS 放入不加锁成功了就直接 break 跳出if (casTabAt(tab, i, null,new NodeK,V(hash, key, value, null)))break; // no lock when adding to empty bin}else if ((fh f.hash) MOVED)tab helpTransfer(tab, f);else {V oldVal null;// 使用 synchronized 加锁加入节点synchronized (f) {if (tabAt(tab, i) f) {// 说明是链表if (fh 0) {binCount 1;// 循环加入新的或者覆盖节点for (NodeK,V e f;; binCount) {K ek;if (e.hash hash ((ek e.key) key ||(ek ! null key.equals(ek)))) {oldVal e.val;if (!onlyIfAbsent)e.val value;break;}NodeK,V pred e;if ((e e.next) null) {pred.next new NodeK,V(hash, key,value, null);break;}}}else if (f instanceof TreeBin) {// 红黑树NodeK,V p;binCount 2;if ((p ((TreeBinK,V)f).putTreeVal(hash, key,value)) ! null) {oldVal p.val;if (!onlyIfAbsent)p.val value;}}}}if (binCount ! 0) {if (binCount TREEIFY_THRESHOLD)treeifyBin(tab, i);if (oldVal ! null)return oldVal;break;}}}addCount(1L, binCount);return null; }工作步骤 初始化使用 cas 来保证并发安全懒惰初始化 table树化当 table.length 64 时先尝试扩容超过 64 时并且 bin.length 8 时会将链表树化树化过程会用 synchronized 锁住链表头 说明锁住某个槽位的对象头是一种很好的细粒度的加锁方式类似 MySQL 中的行锁put如果该 bin 尚未创建只需要使用 cas 创建 bin如果已经有了锁住链表头进行后续 put操作元素添加至 bin 的尾部get无锁操作仅需要保证可见性扩容过程中 get 操作拿到的是 ForwardingNode 会让 get 操作在新 table 进行搜索扩容扩容时以 bin 为单位进行需要对 bin 进行 synchronized但这时其它竞争线程也不是无事可做它们会帮助把其它 bin 进行扩容size元素个数保存在 baseCount 中并发时的个数变动保存在 CounterCell[] 当中最后统计数量时累加 总结 JDK 1.7 和 JDK 1.8实现有什么不同 线程安全实现方式JDK 1.7 采用 Segment 分段锁来保证安全 Segment 是继承自 ReentrantLock。JDK1.8 放弃了 Segment 分段锁的设计采用 Node CAS synchronized 保证线程安全锁粒度更细synchronized 只锁定当前链表或红黑二叉树的首节点。Hash 碰撞解决方法 : JDK 1.7 采用拉链法JDK1.8 采用拉链法结合红黑树链表长度超过一定阈值时将链表转换为红黑树。并发度JDK 1.7 最大并发度是 Segment 的个数默认是 16。JDK 1.8 最大并发度是 Node 数组的大小并发度更大。 ConcurrentHashMap 中的 CAS 应用 ConcurrentHashMap 是 Java 中高效的并发集合类它通过结合使用 CAS 和 synchronized 来保证线程安全性。 CAS用于在没有锁的情况下保证单个桶bucket中的线程安全更新尤其是 putIfAbsent()、replace() 等操作。每个桶内部通常是通过 CAS 来完成插入、删除和更新操作减少了全表锁定的情况提高了性能。 示例 在 ConcurrentHashMap 的 putIfAbsent 方法中CAS 用来判断当前桶内是否已有值如果没有则将新值插入。 void putIfAbsent(K key, V value) {int hash hash(key);NodeK,V node table[hash (table.length - 1)];// 使用 CAS 保证插入操作的线程安全if (node null || cas(node, null, value)) {return value;}return null; }synchronized在一些较为复杂的操作比如扩容、迭代器遍历时中仍然使用 synchronized 来保证线程安全。
通过这样的组合ConcurrentHashMap 既能避免在并发情况下对整个数据结构加锁提高效率又能在需要的时候通过 synchronized 保证一致性。