用闭锁测试HashMap的并发写入问题

今天无意中看到以前写的代码,是一个单例的工厂模式实现,代码片段如下:

 

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越大,效果会越明显。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值