关于hashmap在多线程环境下的一个小实验

我们都知道hashmap是非线程安全的,平时我们经常是在单线程环境下使用这个类的,现在我们模拟一个多线程环境,并发操作访问一个hashmap实例,看看会出现什么匪夷所思的问题。

运行如下程序:

import java.util.HashMap;
public class TestMap {
 private HashMap map = new HashMap(2, 0.5f);
 public TestMap() {
  Thread t1 = new Thread() {
   public void run() {
    for (int i = 0; i < 50000; i++) {
     map.put(new Integer(i), i);
    }
    System.out.println("t1 over");
   }
  };
  Thread t2 = new Thread() {
   public void run() {
    for (int i = 0; i < 50000; i++) {
     map.put(new Integer(i), i);
    }
    System.out.println("t2 over");
   }
  };
  Thread t3 = new Thread() {
   public void run() {
    for (int i = 50000; i < 100000; i++) {
     map.put(new Integer(i), i);
    }
    System.out.println("t3 over");
   }
  };
  Thread t4 = new Thread() {
   public void run() {
    for (int i = 100000; i < 150000; i++) {
     map.put(new Integer(i), i);
    }
    System.out.println("t4 over");
   }
  };
  Thread t5 = new Thread() {
   public void run() {
    for (int i = 150000; i < 200000; i++) {
     map.put(new Integer(i), i);
    }
    System.out.println("t5 over");
   }
  };
  Thread t6 = new Thread() {
   public void run() {
    for (int i = 0; i < 50000; i++) {
     map.get(new Integer(i));
    }
    System.out.println("t6 over");
   }
  };
  Thread t7 = new Thread() {
   public void run() {
    for (int i = 50000; i < 100000; i++) {
     map.get(new Integer(i));
    }
    System.out.println("t7 over");
   }
  };
  Thread t8 = new Thread() {
   public void run() {
    for (int i = 100000; i < 150000; i++) {
     map.get(new Integer(i));
    }
    System.out.println("t8 over");
   }
  };
  t1.start();
  t2.start();
  t3.start();
  t4.start();
  t5.start();
  t6.start();
  t7.start();
  t8.start();
 }
 public static void main(String[] args) {
  new TestMap();
 }
}

刚开始我并未给构造器指定参数,为了提高问题复现的机率,我把map的初始容量和负载因子分别设为2和0.5,这样map的rehash操作就更加频繁了,多点击运行一下,就会发现有几个线程没有打印出结束标志,这是什么原因,难道线程可能进入了等待状态,或者死循环?

查看任务管理器,发现javaw线程cpu竟超过80%

利用jstack工具查看堆栈信息:

线程处于运行状态,程序进入了死循环,多个线程同时put,rehash的时候会导致循环链表的出现,用get方法获取就会出现inifinite loop。(疫苗:Java HashMap的死循环)这个问题现在看来一目了然,但在生产环境上,系统庞大,要找出问题根源是需要费一段时间的,当hashmap出现了让人匪夷所思的现象时,要想想它是否处于多线程环境。

另外,在运行这段代码时,有时也会报出如下异常:

Exception in thread "Thread-2" java.lang.ArrayIndexOutOfBoundsException: 26

at java.util.HashMap.getEntry(HashMap.java:463)

at java.util.HashMap.get(HashMap.java:417)

at map.TestMap$3.run(TestMap.java:36)

直接看源码可知,问题还是出在多个线程同时操作访问table变量上。

或许你在多线程环境下使用hashmap过程中碰到更多有趣的现象,请留言或投稿给我。

原文发布于微信公众号 - java达人(drjava)

原文发表时间:2016-04-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏技术记录

Protobuf3语法详解

9645
来自专栏CodingToDie

java 代理

java 代理 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额...

3514
来自专栏用户2442861的专栏

【深入Java虚拟机】之四:类加载机制

转载请注明出处:http://blog.csdn.net/ns_code/article/details/17881581

591
来自专栏LIN_ZONE

PHP 常用设计模式 (转载)

单例模式顾名思义,就是只有一个实例。作为对象的创建模式, 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

1512
来自专栏蓝天

用 tr 过滤文件

您可以将 tr 看作为 sed 的(极其)简化的变体:它可以用一个字符来替换另一个字符,或者可以完全除去一些字符。您也可以用它来除去重复字符。这就是所有 tr ...

863
来自专栏小灰灰

Nginx 路由转发配置笔记

Nginx 路由转发配置笔记 由于预算有限,只有一台服务器,想要玩的东西不少,所以这个台服务器上会提供多重服务,因此涉及到的nginx转发就必有重要了 由ng...

6306
来自专栏Java学习网

JavaScript依赖注入的实现思路

JavaScript依赖注入的实现思路 如今各个框架都在模块化,连前端的javascript也不例外。每个模块负责一定的功能,模块与模块之间又有相互依赖,那么问...

2106
来自专栏IMWeb前端团队

Promise接口实现之jQuery 的deferred对象

本文作者:IMWeb json 原文出处:IMWeb社区 未经同意,禁止转载 Promise是什么? 我们知道JavaScript是单线程,如果遇到某...

18410
来自专栏数据结构笔记

python爬虫系列之数据的存储(一):json库的使用

在上一篇文章里我们讲了 xpath写法的问题还以爬取我的文章信息写了示例,但是在上一篇中我们只是爬取并打印了信息,并没有对信息进行保存。

2412
来自专栏Java开发者杂谈

Python(1):入门

安装:    在linux中一般都自带有python2.7的版本,如果想升级python到最新的版本可以参考其他博客(http://www.cnblogs.c...

3718

扫码关注云+社区

领取腾讯云代金券