高并发编程之ConcurrentHashMap讲解

一、ConcurrentHashMap介绍
ConcurrentHashMap 和 HashMap 思路是差不多的,但是因为它支持并发操作,所以要复杂一些。
整个 ConcurrentHashMap 由一个个 Segment 组成,Segment 代表”部分“或”一段“的意思,所以很多地方都会将其描述为分段锁。注意,行文中,我很多地方用了“槽”来代表一个 segment。
(简单理解就是,ConcurrentHashMap 是一个 Segment 数组,Segment 通过继承 ReentrantLock 来进行加锁,所以每次需要加锁的操作锁住的是一个 segment,这样只要保证每个 Segment 是线程安全的,也就实现了全局的线程安全)。

二、什么是Segment?
①、ConcurrentHashMap采用了非常精妙的"分段锁"策略,ConcurrentHashMap的主干是个Segment数组。
②、Segment继承了ReentrantLock,所以它就是一种可重入锁(ReentrantLock)。在ConcurrentHashMap,一个Segment就是一个子哈希表,Segment里维护了一个HashEntry数组,并发环境下,对于不同Segment的数据进行操作是不用考虑锁竞争的。(就按默认的ConcurrentLeve为16来讲,理论上就允许16个线程并发执行,有木有很酷)

所以,对于同一个Segment的操作才需考虑线程同步,不同的Segment则无需考虑。
Segment类似于HashMap,一个Segment维护着一个HashEntry数组。

三、ConcurrentHashMap常用方法介绍
1、clear() :从该映射中移除所有映射关系。
2、contains(Object value) :一种遗留方法,测试此表中是否有一些与指定值存在映射关系的键,返回值为Boolean。
3、containsKey(Object key) : 测试指定对象是否为此表中的键,返回值为Boolean。
4、containsValue(Object value) :如果此映射将一个或多个键映射到指定值,则返回 true。
5、entrySet() :返回此映射所包含的映射关系的 Set 视图,返回值为Set<Map.Entry<K,V>>。
6、get(Object key) :返回指定键所映射到的值,如果此映射不包含该键的映射关系,则返回 null。
7、isEmpty() : 如果此映射不包含键-值映射关系,则返回 true。
8、keys() :返回此表中键的枚举,返回值为 Enumeration。
9、keySet() : 返回此映射中包含的键的 Set 视图,返回值为 Set。
10、put(K key, V value) :将指定键映射到此表中的指定值。
11、remove(Object key) :从此映射中移除键(及其相应的值)。
12、remove(Object key, Object value) :只有目前将键的条目映射到给定值时,才移除该键的条目,返回值为Boolean。
13、replace(K key, V value) :只有目前将键的条目映射到某一值时,才替换该键的条目。
14、replace(K key, V oldValue, V newValue) :只有目前将键的条目映射到给定值时,才替换该键的条目,返回值为 boolean。
15、size() :返回此映射中的键-值映射关系数。

四、Java代码示例

package chapter3.concurrenthashmap;

import com.sun.org.apache.xpath.internal.operations.Bool;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author czd
 */
public class ConcurrentHashMapTest {
    public static void main(String[] args) {
        /**
         *构造方法摘要:
         * 1.1、ConcurrentHashMap():
         *          创建一个带有默认初始容量 (16)、加载因子 (0.75) 和 concurrencyLevel (16) 的新的空映射。
         * 1.2、ConcurrentHashMap(int initialCapacity):
         *          创建一个带有指定初始容量、默认加载因子 (0.75) 和 concurrencyLevel (16) 的新的空映射。
         */
        ConcurrentHashMap<String,Integer> concurrentHashMap = new ConcurrentHashMap<>(10);
        /**
         * 1、	put(K key, V value):将指定键映射到此表中的指定值
         */
        for (int i = 0; i < 20; i++){
            concurrentHashMap.put("" + i , i);
        }

        /**
         * 2、entrySet():返回此映射所包含的映射关系的 Set 视图,返回Set<Map.Entry<K,V>>
         *
         */
        final Set<Map.Entry<String, Integer>> entries = concurrentHashMap.entrySet();
        for(Map.Entry<String , Integer> entry : entries){
            System.out.println("Key:" + entry.getKey() + " Value:" + entry.getValue());
        }
        /**
         * 注意:一般使用如下方法遍历ConcurrentHashMap
         */

//        for(Map.Entry<String , Integer> entry : concurrentHashMap.entrySet()){
//            System.out.println("Key:" + entry.getKey() + " Value:" + entry.getValue());
//        }

        /**
         * 3、contains(Object value) :一种遗留方法,测试此表中是否有一些与指定值存在映射关系的键,返回值为Boolean。
         */
        Boolean contains2Boolean = concurrentHashMap.contains(2);
        System.out.println("concurrentHashMap是否包含Value值为2的值:" + contains2Boolean);
        Boolean contains15Boolean = concurrentHashMap.contains(15);
        System.out.println("concurrentHashMap是否包含Value值为15的值:" + contains15Boolean);

        /**
         * 4、ontainsKey(Object key) :测试指定对象是否为此表中的键,返回值为Boolean。
         */

        Boolean contains2Key = concurrentHashMap.containsKey("2");
        System.out.println("concurrentHashMap是否包含Key值为2的键:" + contains2Key);
        Boolean contains15Key = concurrentHashMap.containsKey("15");
        System.out.println("concurrentHashMap是否包含Key值为15的键:" + contains15Key);

        /**
         * 5、containsValue(Object value) :如果此映射将一个或多个键映射到指定值,则返回 true。
         */
        Boolean contains3Boolean = concurrentHashMap.containsValue(3);
        System.out.println("concurrentHashMap是否包含Value值为3的值:" + contains3Boolean);
        Boolean contains16Boolean = concurrentHashMap.containsValue(16);
        System.out.println("concurrentHashMap是否包含Value值为16的值:" + contains16Boolean);

        /**
         * 6、isEmpty():如果此映射不包含键-值映射关系,则返回 true。
         */
        Boolean isEmptyBoolean = concurrentHashMap.isEmpty();
        System.out.println("concurrentHashMap是否为空:" + isEmptyBoolean);

        /**
         * 7、keySet() :返回此映射中包含的键的 Set 视图。
         */
        Set<String> keySet = concurrentHashMap.keySet();
        for (String key : keySet){
            System.out.println("concurrentHashMap中的Key键:" + key);
        }

        /**
         * 8、remove(Object key):从此映射中移除键(及其相应的值)。
         */
        Integer beforeRemove = concurrentHashMap.get("10");
        System.out.println("beforeRemove: " + beforeRemove);
        concurrentHashMap.remove("10");
        Integer afterRemove = concurrentHashMap.get("10");
        System.out.println("afterRemove: " + afterRemove);

        /**
         * 9、remove(Object key, Object value):只有目前将键的条目映射到给定值时,才移除该键的条目。
         */
        Integer beforeMove = concurrentHashMap.get("9");
        System.out.println("beforeRemove: " + beforeMove);
        boolean removeError = concurrentHashMap.remove("9", 8);
        boolean removeTrue = concurrentHashMap.remove("9", 9);
        System.out.println("键值匹配>>>移除成功?:" + removeTrue + "  键值不匹配>>>移除成功?:" + removeError);
        Integer afterMove = concurrentHashMap.get("9");
        System.out.println("afterMove: " + afterMove);

        /**
         * 10、replace(K key, V value) :只有目前将键的条目映射到某一值时,才替换该键的条目。
         */
        Integer beforeReplace = concurrentHashMap.get("8");
        System.out.println("beforeReplace: " + beforeReplace);
        concurrentHashMap.replace("8" , 28);
        Integer afterReplace = concurrentHashMap.get("8");
        System.out.println("afterReplace: " + afterReplace);

        /**
         * 11、replace(K key, V oldValue, V newValue):
         *           只有目前将键的条目映射到给定值时,才替换该键的条目,返回值为Boolean。
         */
        Integer beforeRep = concurrentHashMap.get("6");
        System.out.println("beforeRep: " + beforeRep);
        Boolean replaceError = concurrentHashMap.replace("6" , 16 , 26);
        Boolean replaceTrue = concurrentHashMap.replace("6" , 6 , 26);
        System.out.println("键值匹配>>>替换成功?:" + replaceTrue + "  键值不匹配>>>替换成功?:" + replaceError);
        Integer afterRep = concurrentHashMap.get("6");
        System.out.println("afterRep: " + afterRep);

        /**
         * 12、size() :返回此映射中的键-值映射关系数。
         */
        Integer size = concurrentHashMap.size();
        System.out.println("关系数:" + size);


    }
}

五、总结
ConcurrentHashMap代替同步的Map(Collections.synchronized(new HashMap())),众所周知,HashMap是根据散列值分段存储的,同步Map在同步的时候锁住了所有的段,而ConcurrentHashMap加锁的时候根据散列值锁住了散列值锁对应的那段,因此提高了并发性能。

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ConcurrentHashMap是一个专为并发场景而设计的哈希表,它是基于HashMap实现的。在多线程并发的情况下,HashMap是线程不安全的,可能会引发死循环、死锁等问题。尽管在JDK8之后HashMap解决了死锁问题,但仍然存在其他多线程问题,例如数据丢失。为了解决这些问题,引入了ConcurrentHashMapConcurrentHashMap的实现机制是将整个哈希表分为多个Segment段,每个Segment都是一个独立的哈希表,这些Segment共同保存在一个名为segments的数组中。通过这种方式,ConcurrentHashMap实现了对不同Segment的并发访问,从而提了并发性能。 在JDK 1.7版本中,ConcurrentHashMap的实现方式与HashMap基本相同,只是将操作放在单线程中执行,避免了HashMap在扩容时可能出现的死循环问题,从而保证了线程安全性。 总的来说,ConcurrentHashMap通过分段锁的方式,提供了更好的并发性能,解决了Java中并发环境下HashMap的线程安全问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [JAVA并发集合之ConcurrentHashMap](https://blog.csdn.net/huxing998/article/details/129157146)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值