HashMap
本文记述一次hashMap引起阻塞问题
问题现象:
程序是将一个数据库里面的数据导入到另外一个数据库中,两边表结构不一样但业务是一致的(mysql->mssql)。由于每次都是全量循环校验导入,所以运行时间要2-3个小时。
运行过程中,发现在调用jdbcTemplate查询的过程中,经常发生阻塞。
问题分析:
一开始以为,是数据库连接池问题或网络较慢,一直在等待数据库连接或数据库服务器端任务阻塞,一直等待执行
光靠猜想是没有道理的,还是dump看下,
"Thread-1" prio=6 tid=0x000000000b365000 nid=0x15e8 runnable [0x000000000d2af000]
java.lang.Thread.State: RUNNABLE
at java.util.HashMap.getEntry(HashMap.java:446)
at java.util.HashMap.containsKey(HashMap.java:434)
at java.util.HashSet.contains(HashSet.java:201)
"Thread-0" prio=6 tid=0x000000000b364800 nid=0x714 runnable [0x000000000ca7e000]
java.lang.Thread.State: RUNNABLE
at java.util.HashMap.getEntry(HashMap.java:446)
at java.util.HashMap.containsKey(HashMap.java:434)
at java.util.HashSet.contains(HashSet.java:201)
final Entry<K,V> getEntry(Object key) {
int hash = (key == null) ? 0 : hash(key);
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
应该是在e = e.next一直循环,那为什么会形成环呢?
然后各种baidu,google,在多线程情况下,hashMap扩容的时候,可能生成环
/**
* Transfers all entries from current table to newTable.
*/
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry<K,V> e : table) {
while(null != e) {
Entry<K,V> next = e.next;
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
}
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
}
}
}
扩容时,会将旧表里面的数据复制到新扩容的表中,该任务由transfer方法执行
引用
线程一,执行上述transfer代码:
线程一:
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry<K,V> e : table) {
while(null != e) {
Entry<K,V> next = e.next;
//线程一在这里休眠
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
}
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
}
}
}
这时,线程1线程栈中,e为3,next值为7
然后,线程2执行上述代码,最终将结点3,结点7放入新表中,即: 7和3在table下标为3中,7->3
在这个过程中,线程2修改了引用结点7,使其中的next字段指向了3(这就是引起闭环的主要原因)
接着线程一继续执行,当前e为3,next为7
第一步,将当前处理的结点3放入新表newTable(下标为3),然后将结点3的next指向null(因此newTable是处于线程栈中,是线程私有的,并不受线程2影响)
这部处理完后,newTable下标为3的内容为:3(其next指向null)
第二步,处理结点7,这时当前结点e为7,而next由于线程2修改了其引用,所以next为3。
这步处理完后,其newTable下标为3的内容为:7(指向3),3(指向null)
第三步,这步是引起闭环的最终原因,当前处理结点为3,next值为null
这时使3指向newTable中的7,然后将3存入newTable
这步处理完后,newTable下标为3的内容为:
3(指向7),7(指向3)。
查找时,查找key为11的值,这时查找table下标为3的内容,先找3,不匹配,然后找7.也不对,这时查7指向的3.。。。。
死循环
参考:
【java基础 12】HashMap中是如何形成环形链表的?
http://blog.csdn.net/hhx0626/article/details/54024222
HashMap并发情况下,导致闭环链
http://blog.csdn.net/zhaozhenzuo/article/details/18800063
并发环境下HashMap引起full gc排查
http://blog.lichengwu.cn/java/2015/04/06/case-of-hashmap-in-concurrency/
多线程下HashMap的死循环问题
http://www.cnblogs.com/ITtangtang/p/3966467.html
分享到:
相关推荐
1. **非同步**:HashMap不是线程安全的,这意味着在多线程环境中,如果不采取同步措施,可能会出现数据不一致的情况。如果需要线程安全的Map,可以考虑使用ConcurrentHashMap。 2. **允许null键和null值**:HashMap...
在分析“c_hashmap-master”的源代码时,我们需要特别关注这些关键部分,理解它们是如何协同工作的。同时,由于这是个C语言实现,所以内存管理(如malloc和free)和错误处理是需要特别关注的方面。 总结来说,"c_...
然而,`HashMap`并非线程安全,这意味着在多线程环境中直接使用`HashMap`可能会导致数据不一致、并发问题,甚至程序崩溃。本项目“hashmap-thread-test”显然是为了测试和展示这一特性。 ### Java HashMap 的特性 ...
标题"HashMap-master.zip_hash"可能指的是一个关于HashMap实现或优化的项目,其中包含了哈希函数的设计和分析。 哈希表的核心思想是通过哈希函数将键(Key)映射到数组的特定位置,使得我们能够以近乎常数的时间...
在Java的HashMap中,多线程并发环境下的扩容操作可能会引发死锁问题。这主要发生在JDK 1.7版本,因为其扩容机制采用了头插法。以下详细解释这个问题及其解决方案。 首先,HashMap的扩容机制是在容量达到阈值时触发...
### HashMap的Hash原理详解 #### 一、概述 在Java编程语言中,`HashMap`是实现`Map`接口的...通过以上分析,我们可以更加深入地理解`HashMap`内部的工作机制,这对于理解和优化基于`HashMap`的应用程序具有重要意义。
同时,这也是一种优化,因为避免了因多次声明变量导致的额外内存开销。 值得注意的是,尽管"grunt-hashmap-ext"提供了便利,但它并不适用于所有场景。在某些情况下,例如在需要长期存储或跨函数共享数据时,传统的...
Java、hashMap
4. 避免在多线程环境中直接使用HashMap:如果你确定不需要在多线程环境下共享HashMap,那么可以考虑局部变量的方式,只在单个线程中使用HashMap,这样就无需担心线程安全问题。 总结起来,理解HashMap的线程不安全...
### HashMap多线程解决方案 #### 一、引言 在多线程环境下,Java的`HashMap`类在处理并发操作时容易出现线程安全问题。本文档深入探讨了`HashMap`在多线程环境中可能遇到的安全问题,并提出了一系列可行的解决方案...
Java中的多线程编程是开发高并发应用的关键技术之一,涉及到如何有效管理和利用系统资源,尤其是在处理并发数据访问时,确保数据的安全性和一致性至关重要。在Java中,有多种方式可以实现线程间的数据共享和对象独立...
- **多线程优点**:提高系统资源利用率,提高程序响应速度,实现并发执行,提升整体性能。 2. **线程执行任务** - **创建线程**:在Java等语言中,可以通过继承Thread类或者实现Runnable接口来创建线程。 - **...
- 不是线程安全的,如果在多线程环境下使用,需要手动同步或使用ConcurrentHashMap。 - 默认负载因子为0.75,当HashMap的容量达到这个比例时,会自动进行扩容操作,以保持良好的性能。 5. **项目"Generic-HashMap...
该项目为基于Java并发编程的ConcurrentHashMap测试设计源码,共包含24个文件,其中Java源文件21个,Git忽略文件1个,Markdown文档1个,XML配置文件1个。...关注抖音“跟大佳一起学架构”获取更多相关内容。
Java集合框架中的某些类(如`ArrayList`、`HashMap`)默认是非线程安全的,即它们没有提供同步机制来防止多线程环境下的并发修改异常。为了解决这个问题,可以采取以下措施: - 使用同步容器:如`Vector`、`...
在多线程环境中,为了保证数据的一致性和正确性,通常需要引入锁机制,但这会增加额外的开销,降低并发性能。Go语言提供了通道(Channel)和原子操作(Atomic Operations)等原生并发工具,使得无锁实现成为可能。 ...
- 集合框架:掌握ArrayList、LinkedList、HashMap、HashSet等容器的使用及其原理。 - 泛型:了解泛型的作用,如何使用泛型类和泛型方法。 - I/O流:理解流的概念,学习字节流和字符流,以及缓冲流的使用。 2. **...
01-HashMap底层数据结构分析.mp4
读取excel文件数据,封装成hashmap-附件资源