今天无意中看到以前写的代码,是一个单例的工厂模式实现,代码片段如下:
private static Map daoMap = new HashMap();
public static Dao createDao(String className) {
Dao dao = (Dao) daoMap.get(className);
if (dao != null) {
return dao;
} else {
dao = (Dao) Class.forName(className).newInstance();
daoMap.put(className, dao);
return dao;
}
}
这段代码是在一个Java EE项目的一个工厂类里发现的,今天看来,在并发稍大点儿的时候,它就会出现问题,因为HashMap是线程不安全的。于是写了段代码测试一下HashMap在并发写入时会出什么问题。
测试类:
public class Test {
static Map<String,String> map = new HashMap();
static int N = 1000;
static CountDownLatch startSignal = new CountDownLatch(1);//闭锁
static CountDownLatch doneSignal = new CountDownLatch(N);
/**
* @param args
*/
public static void main(String[] args) {
for (int i = 0; i < N; i++) {
final int j = i;
new Thread(new Runnable(){
public void run() {
try {
startSignal.await();//使当前线程在锁存器倒计数至零之前一直等待
} catch (InterruptedException e) {
e.printStackTrace();
}
map.put(Thread.currentThread().getId()+""+j, "test");
doneSignal.countDown();
}
}).start();
}
startSignal.countDown();//递减锁存器的计数,如果计数到达零,则释放所有等待的线程
try {
doneSignal.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("done,size:" + map.size());
}
}
上面的测试类里用到了一个jdk1.5里出现的类CountDownLatch,闭锁。因为我们要在所有线程结束后,来检验map的size。
测试结果:
done,size:948
可见,HashMap出了问题,1000个不重复的元素只放进去948个,如果加大N的值,程序就会陷入死循环。
解决方案是将HashMap换成ConcurrentHashMap,也是jdk1.5以后才有的类。它的并发性能要比Hashtable好。
使用N=7000,进行测试:
ConcurrentHashMap测试的最好结果是:
done,size:7000, time:1735
Hashtable的最好结果是:
done,size:7000, time:1800
如果N越大,效果会越明显。
分享到:
相关推荐
4. 避免在多线程环境中直接使用HashMap:如果你确定不需要在多线程环境下共享HashMap,那么可以考虑局部变量的方式,只在单个线程中使用HashMap,这样就无需担心线程安全问题。 总结起来,理解HashMap的线程不安全...
然而,对于多线程环境,HashMap并不是线程安全的,这在并发编程中可能会引发一系列问题。本篇将深入探讨HashMap的线程安全问题,并提供相关的解决方案。 首先,我们需要了解HashMap在多线程环境下可能出现的问题: ...
此外,引入了ConcurrentHashMap类,这是一个专门为多线程设计的高效容器,其内部使用分段锁策略,可以在并发环境下保证线程安全,避免了类似HashMap扩容引发的死锁问题。 如果你在多线程环境中使用HashMap并遇到...
5. HashMap的并发问题如何解决? 答:在多线程环境下,可以使用ConcurrentHashMap,它是线程安全的HashMap实现。 五、HashMap与HashSet的关系 HashSet基于HashMap实现,每个元素作为HashMap的一个键,值为null。...
TBB 开源库及并发 Hashmap 的使用 TBB 开源库是 Intel 公司开发的开源并行计算库,用于在多核平台上进行并行化程序的开发。该库使用标准 C++ 编写,提供了一个灵活的框架来实现数据并行计算。使用 TBB 可以使用户...
通过上述介绍,我们可以看到使用 `HashMap` 解决 ibatis 中的动态列名和列数的问题是一种非常实用的方法。它不仅避免了为每种情况创建实体类的繁琐工作,还提高了代码的灵活性和可维护性。希望本文能够帮助你在实际...
### HashMap介绍和使用详解 #### 一、HashMap的数据结构 HashMap是Java集合框架的一个重要组成部分,它实现了Map接口,能够存储键值对映射。在Java编程语言中,最基本的数据结构有两种:数组和引用(模拟指针)。...
然而,`HashMap`并非线程安全,这意味着在多线程环境中直接使用`HashMap`可能会导致数据不一致、并发问题,甚至程序崩溃。本项目“hashmap-thread-test”显然是为了测试和展示这一特性。 ### Java HashMap 的特性 ...
总的来说,马士兵老师的HashMap学习笔记不仅涵盖了HashMap的基础知识,还深入探讨了其在不同JDK版本中的实现细节,特别是并发环境下的问题和解决方案。理解这些内容对于提升Java编程技能和优化代码性能具有重要价值...
如果多个线程并发地访问并修改`HashMap`,则可能导致数据不一致性问题。为了在多线程环境中安全地使用`HashMap`,开发者需要自己负责同步,例如使用`Collections.synchronizedMap(new HashMap,V>())`创建线程安全的`...
4. **并发问题**:HashMap不是线程安全的,这意味着在多线程环境中,同时对HashMap进行读写操作可能会导致数据不一致。如果需要线程安全的哈希表,可以使用`ConcurrentHashMap`。 5. **null值**:HashMap允许键和值...
- 注意HashMap的并发问题,如果在多线程环境下,使用Collections.synchronizedMap()或使用ConcurrentHashMap来保证线程安全。 总结起来,HashMap和HashSet是Java集合框架的重要组成部分,它们利用哈希技术提供了...
如果存在冲突(多个键映射到同一个位置),HashMap通常会使用链表或红黑树来处理这些冲突,确保查找效率仍然保持较高。 为了实现词典查询,我们需要以下步骤: 1. **读取字典文件**:字典文件通常包含一系列词条,...
文档中的代码示例展示了一种使用HashMap作为缓存的常见模式:单例模式下的缓存管理。以下是对代码关键部分的解析: 1. **初始化HashMap**:`protected static final HashMap map = new HashMap();` 这一行代码创建...
HashMap 使用链表来解决哈希冲突的问题,即当两个键的哈希值相同时,HashMap 使用链表来存储这些键值对。 HashMap 的应用场景 1. 缓存机制:HashMap 可以用来实现缓存机制,例如缓存用户信息、缓存查询结果等。 2....
`HashMap`在设计时并未考虑线程安全,因此在并发场景下,如果不采取适当的同步措施,可能会遇到诸如数据丢失、死锁等问题。 `HashMap`的核心实现是基于哈希表的,它使用了数组和链表的数据结构。当多个线程同时对`...
哈希映射(HashMap)是Java编程语言中广泛使用的数据结构之一,主要提供键值对的存储和查找功能。HashMap的实现基于哈希表的概念,它通过计算对象的哈希码来快速定位数据,从而实现了O(1)的平均时间复杂度。在深入...
因此,在多线程环境中使用`HashMap`时,如果不采取额外的同步措施,可能会导致数据不一致或其他并发问题。 #### 2. 同步机制 - **Hashtable**: 使用内部同步机制来确保线程安全,这意味着在执行关键操作时会锁定...
- **HashMap**: 相对于`HashTable`,`HashMap`在单线程或低并发情况下具有更好的性能。这是因为`HashMap`没有同步开销,因此操作速度更快。 #### 四、内部实现细节 - **HashTable**: 内部使用了`Entry`类来表示...