装载:http://blog.csdn.net/jiafu1115/article/details/7574350
大家都知道HashMap不是线程安全的,但是大家的理解可能都不是十分准确。很显然读写同一个key会导致不一致大家都能理解,但是如果读写一个不变的对象会有问题么?看看下面的代码就明白了。
1 import java.util.HashMap;
2 import java.util.Map;
3 import java.util.Random;
4 import java.util.concurrent.ExecutorService;
5 import java.util.concurrent.Executors;
6 import java.util.concurrent.TimeUnit;
7 import java.util.concurrent.atomic.AtomicInteger;
8
9 public class HashMapTest2 {
10 static void doit() throws Exception{
11 final int count = 200;
12 final AtomicInteger checkNum = new AtomicInteger(0);
13 ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(100);
14 //
15 final Map<Long, String> map = new HashMap<Long, String>();
16 map.put(0L, "www.imxylz.cn");
17 //map.put(1L, "www.imxylz.cn");
18 for (int j = 0; j < count; j++) {
19 newFixedThreadPool.submit(new Runnable() {
20 public void run() {
21 map.put(System.nanoTime()+new Random().nextLong(), "www.imxylz.cn");
22 String obj = map.get(0L);
23 if (obj == null) {
24 checkNum.incrementAndGet();
25 }
26 }
27 });
28 }
29 newFixedThreadPool.awaitTermination(1, TimeUnit.SECONDS);
30 newFixedThreadPool.shutdown();
31
32 System.out.println(checkNum.get());
33 }
34
35 public static void main(String[] args) throws Exception{
36 for(int i=0;i<10;i++) {
37 doit();
38 Thread.sleep(500L);
39 }
40 }
41 }
42
结果一定会输出0么?结果却不一定。比如某一次的结果是:
0
3
0
0
0
0
9
0
9
0
查看了源码,其实出现这个问题是因为HashMap在扩容是导致了重新进行hash计算。
在HashMap中,有下面的源码:
1 public V get(Object key) {
2 if (key == null)
3 return getForNullKey();
4 int hash = hash(key.hashCode());
5 for (Entry<K,V> e = table[indexFor(hash, table.length)];
6 e != null;
7 e = e.next) {
8 Object k;
9 if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
10 return e.value;
11 }
12 return null;
13 }
2 if (key == null)
3 return getForNullKey();
4 int hash = hash(key.hashCode());
5 for (Entry<K,V> e = table[indexFor(hash, table.length)];
6 e != null;
7 e = e.next) {
8 Object k;
9 if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
10 return e.value;
11 }
12 return null;
13 }
在indexOf中就会导致计算有偏移。
1 static int indexFor(int h, int length) {
2 return h & (length-1);
3 }
很显然在Map的容量(table.length,数组的大小)有变化时就会导致此处计算偏移变化。这样每次读的时候就不一定能获取到目标索引了。为了证明此猜想,我们改造下,变成以下的代码。
final Map<String, String> map = new HashMap<String, String>(10000);
执行多次结果总是输出:
0
0
0
0
0
0
0
0
0
0
当然了如果只是读,没有写肯定没有并发的问题了。改换Hashtable或者ConcurrentHashMap肯定也是没有问题了
相关推荐
但是需要注意,虽然这个方法可以保证基本的线程安全,但迭代仍然是非线程安全的,即不能在遍历过程中修改Map。 2. 使用ConcurrentHashMap:Java从1.5版本开始引入了ConcurrentHashMap,它是线程安全且高并发性能的...
经常会看到说HashMap是线程不安全的,ConcurrentHashMap是线程安全的等等说法,不禁有个疑问,什么是线程安全?什么样的类是线程安全的? 1.什么是线程安全性(what) 线程安全定义,最核心是正确性, 正确性:多个...
然而,对于多线程环境,HashMap并不是线程安全的,这在并发编程中可能会引发一系列问题。本篇将深入探讨HashMap的线程安全问题,并提供相关的解决方案。 首先,我们需要了解HashMap在多线程环境下可能出现的问题: ...
`HashMap`在设计时并未考虑线程安全,因此在并发场景下,如果不采取适当的同步措施,可能会遇到诸如数据丢失、死锁等问题。 `HashMap`的核心实现是基于哈希表的,它使用了数组和链表的数据结构。当多个线程同时对`...
HashMap和HashTable的区别?但是如果想线程安全有想效率高?
Servlet 线程安全问题是指在使用 Servlet 编程时,如果不注意多线程安全性问题,可能会导致难以发现的错误。Servlet/JSP 技术由于其多线程运行而具有很高的执行效率,但这也意味着需要非常细致地考虑多线程的安全性...
然而,`HashMap`并非线程安全,这意味着在多线程环境中直接使用`HashMap`可能会导致数据不一致、并发问题,甚至程序崩溃。本项目“hashmap-thread-test”显然是为了测试和展示这一特性。 ### Java HashMap 的特性 ...
在并发环境下,HashMap的非线程安全可能导致死循环(例如,多个线程同时进行扩容操作)和其他并发问题。 了解Map的整体结构也很重要,HashMap和其他Map实现如LinkedHashMap(保持插入顺序或访问顺序的HashMap)都是...
模拟面试之HashMap ...\ ...7.HashMap是线程安全的吗? 追问:如何解决这个线程不安全的问题? 追问:分别讲一下这几种Map都是如何实现线程安全的? 8.说一下HashMap在JDK1.8中都有哪些改变? 9.HashM
计算机技术、IT咨询、人工智能AI理论介绍,学习参考资料计算机技术、IT咨询、人工智能AI理论介绍,学习参考资料计算机技术、IT咨询、人工智能AI理论介绍,学习参考资料计算机技术、IT咨询、人工智能AI理论介绍,学习...
答:在多线程环境下,可以使用ConcurrentHashMap,它是线程安全的HashMap实现。 五、HashMap与HashSet的关系 HashSet基于HashMap实现,每个元素作为HashMap的一个键,值为null。因此,HashSet的操作性能也依赖于...
此外,引入了ConcurrentHashMap类,这是一个专门为多线程设计的高效容器,其内部使用分段锁策略,可以在并发环境下保证线程安全,避免了类似HashMap扩容引发的死锁问题。 如果你在多线程环境中使用HashMap并遇到...
3. **为什么不在一开始就使用红黑树?** 这是考虑到空间和性能之间的平衡。红黑树节点占用的空间是链表节点的两倍,所以只有当链表足够长时,转换才划算。转换的阈值(默认8)是根据哈希冲突的概率和一般应用需求来...
HashMap 是线程不安全的,可以通过以下三种方式解决线程安全问题: 1. Hashtable(以过时),是在底层哈希表添加了一把锁 synchronized; 2. ConcurrentHashMap,jdk1.7 添加了分段锁,就是在底层数组上,几个索引...
以结构图记录自己的记录自己面对的感触
#### 二、HashMap线程安全问题分析 在多线程环境中,`HashMap`的主要线程安全问题包括但不限于: 1. **链表死循环问题**:在JDK 1.7中,当多个线程同时进行`put`操作时,可能会出现链表死循环的情况,这是一个严重...
本文将深入探讨如何利用Go语言构建一个无锁线程安全的HashMap,特别关注其优化读取访问速度的设计策略。 HashMap是编程中常见的数据结构,用于存储键值对。在多线程环境中,为了保证数据的一致性和正确性,通常需要...
1. 线程安全:HashMap不是线程安全的,而HashTable是线程安全的。 2. 性能:HashMap的性能比HashTable好,因为HashMap使用数组和链表来存储键值对,而HashTable使用链表来存储键值对。 3. null键:HashMap允许存放...
线程安全是指一个类或者方法在多线程环境中被调用时,能够正确地处理并发访问,不会因为线程间的交互而产生错误或不确定的行为。在Java中,线程安全的集合主要分为三类:同步集合、并发集合和不可变集合。 1. 同步...
然而,并非所有集合类都是线程安全的,这在多线程环境中可能导致数据不一致或者运行时异常。线程安全指的是一个对象在多线程环境下可以被正确地访问和修改,而不会出现竞态条件或死锁等问题。 线程不安全的集合类...