zoukankan      html  css  js  c++  java
  • HashMap在高并发下如果没有处理线程安全会有怎样的安全隐患,具体表现是什么

    Hashmap在并发环境下,可能出现的问题:
    1、多线程put时可能会导致get无限循环,具体表现为CPU使用率100%;
    原因:在向HashMap put元素时,会检查HashMap的容量是否足够,如果不足,则会新建一个比原来容量大两倍的Hash表,然后把数组从老的Hash表中迁移到新的Hash表中,迁移的过程就是一个rehash()的过程,多个线程同时操作就有可能会形成循环链表,所以在使用get()时,就会出现Infinite Loop的情况

    // tranfer()片段
    // 这是在resize()中调用的方法,resize()就是HashMap扩容的方法     
    for (int j = 0; j < src.length; j++) {
        Entry e = src[j];
        if (e != null) {
         src[j] = null;
         do {
         Entry next = e.next;  //假设线程1停留在这里就挂起了,线程2登场
         int i = indexFor(e.hash, newCapacity);
         e.next = newTable[i];
         newTable[i] = e;
         e = next;
         } while (e != null);
       }
    }
    

    线程一:Thread1影响key1

    线程二:Thread1影响key2

    因为两条线程的影响,倒是出现循环的情况

    出现问题的测试代码:

    import java.util.HashMap;
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class MyThread extends Thread {
        /**
         * 类的静态变量是各个实例共享的,因此并发的执行此线程一直在操作这两个变量
         * 选择AtomicInteger避免可能的int++并发问题
         */
        private static AtomicInteger ai = new AtomicInteger(0);
        //初始化一个table长度为1的哈希表
        private static HashMap<Integer, Integer> map = new HashMap<Integer, Integer>(1);
        //如果使用ConcurrentHashMap,不会出现类似的问题
    //       private static ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<Integer, Integer>(1);
    
        public void run() {
            while (ai.get() < 100000) {  //不断自增
                map.put(ai.get(), ai.get());
                ai.incrementAndGet();
            }
    
            System.out.println(Thread.currentThread().getName() + "线程即将结束");
        }
    
        public static void main(String[] args) {
            MyThread t0 = new MyThread();
            MyThread t1 = new MyThread();
            MyThread t2 = new MyThread();
            MyThread t3 = new MyThread();
            MyThread t4 = new MyThread();
            MyThread t5 = new MyThread();
            MyThread t6 = new MyThread();
            MyThread t7 = new MyThread();
            MyThread t8 = new MyThread();
            MyThread t9 = new MyThread();
    
            t0.start();
            t1.start();
            t2.start();
            t3.start();
            t4.start();
            t5.start();
            t6.start();
            t7.start();
            t8.start();
            t9.start();
    
        }
    }
    

    2、多线程put时可能导致元素丢失
    原因:当多个线程同时执行addEntry(hash,key ,value,i)时,如果产生哈希碰撞,导致两个线程得到同样的bucketIndex去存储,就可能会发生元素覆盖丢失的情况

    void addEntry(int hash, K key, V value, int bucketIndex) {
        //多个线程操作数组的同一个位置
        Entry<K,V> e = table[bucketIndex];
            table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
            if (size++ >= threshold)
                resize(2 * table.length);
        }
    

    建议:
    使用Hashtable 类,Hashtable 是线程安全的;
    使用并发包下的java.util.concurrent.ConcurrentHashMap,ConcurrentHashMap实现了更高级的线程安全;
    或者使用synchronizedMap() 同步方法包装 HashMap object,得到线程安全的Map,并在此Map上进行操作。

  • 相关阅读:
    .NetCore Grpc 客服端 工厂模式配置授权
    DOCKER 拉取 dotnet 镜像太慢 docker pull mcr.microsoft.com too slow
    Introducing .NET 5
    VSCode 出现错误 System.IO.IOException: The configured user limit (128) on the number of inotify instances has been reached.
    Omnisharp VsCode Attaching to remote processes
    zookeeper3.5.5 centos7 完全分布式 搭建随记
    Hadoop2.7.7 centos7 完全分布式 配置与问题随记
    MySQL索引 索引分类 最左前缀原则 覆盖索引 索引下推 联合索引顺序
    SQL基础随记3 范式 键
    MySQL调优 优化需要考虑哪些方面
  • 原文地址:https://www.cnblogs.com/androidsuperman/p/9008243.html
Copyright © 2011-2022 走看看