今天看啥  ›  专栏  ›  soyoungboy

HashMap在高并发下如果没有处理线程安全会有怎样的安全隐患,具体表现是什么

soyoungboy  · 掘金  ·  · 2018-05-15 09:36
西北野狼
我的github: https://github.com/soyoungboy
我的segmentfault: http://segmentfault.com/u/soyoungboy

【不积跬步,无以至千里;不积小流,无以成江海】
博客园   首页   新随笔   联系   订阅 订阅  管理

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上进行操作。

posted on 2018-05-08 14:57 西北野狼 阅读(16) 评论(0) 编辑 收藏 刷新评论刷新页面返回顶部 注册用户登录后才能发表评论,请 登录注册访问网站首页。
  • 【推荐】超50万VC++源码: 大型组态工控、电力仿真CAD与GIS源码库!
  • 【活动】2050 大会 - 年青人因科技而团聚(5.26-5.27 杭州·云栖小镇)
  • 【推荐】跟最课程陆敏技学Java,5个月高薪就业
  • 【推荐】华为云DevCloud精彩活动集结,重磅福利,免费领取!
  • 【活动】腾讯云云服务器新购特惠,5折上云
  • 【大赛】2018首届“顶天立地”AI开发者大赛
  • 腾讯云0509 最新IT新闻:
    · 在金融业工作了六年,给想入这行的说几个经验
    · 300多位学者联名上书,员工离职,会让谷歌停止与美国国防部合作吗?
    · 外国程序员发帖求助:快四十岁了,不知道以后该怎么办
    · 口碑APP试水手机提前点单功能:将在全国开通
    · 途牛目的地频道上线 于敦德:全面拓展目的地服务网络
    » 更多新闻... 最新知识库文章:
    · 评审的艺术——谈谈现实中的代码评审
    · 如何高效学习
    · 如何成为优秀的程序员?
    · 菜鸟工程师的超神之路 -- 从校园到职场
    · 如何识别人的技术能力和水平?
    » 更多知识库文章... 昵称:西北野狼
    园龄:4年9个月
    粉丝:35
    关注: 4 +加关注
    < 2018年5月 >
    29 30 1 2 3 4 5
    6 7 8 9 10 11 12
    13 14 15 16 17 18 19
    20 21 22 23 24 25 26
    27 28 29 30 31 1 2
    3 4 5 6 7 8 9

    搜索

       

    常用链接

    我的标签

    随笔分类

    随笔档案

    My github

    我的个人博客站点

    积分与排名

    • 积分 - 122299
    • 排名 - 2527

    最新评论

    阅读排行榜

    评论排行榜

    推荐排行榜

    Powered by: 博客园 模板提供:沪江博客 Copyright ©2018 西北野狼


    原文地址:访问原文地址
    快照地址: 访问文章快照