编程错误实例的剖析[3]Map的keySet遍历

3 篇文章 0 订阅

“Java中到底是Map依赖Set还是Set依赖Map?”

初学Java时曾经被老师考过的一个基础问题,在自己的数学印象里,集合的结构要比映射的结构简单;但实际上,Java的Set确实依赖Map实现的,在HashSet的源码中,存在着一个Map成员。这样一个基础的问题成了本次错误的根源。


本次的情况及其简单,在并发的情况下,存在着一个共享的Hashtable

一个线程使用keySet方法得到其key集合,并对该集合进行遍历。

另一个线程对Hashtable进行put操作,此时出现ConcurrentModificationException

public static void main(String[] args) {
		final Map<Integer,String> te = new Hashtable<>();
		te.put(1,"a");
		te.put(15,"a");
		final Set<Integer> keys = te.keySet();
		
		
		Runnable r1 = new Runnable(){
			@Override
			public void run(){
				try {
					Thread.sleep(3000);
					te.put(6,"a");
					System.out.println("insert!");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};
		
		Runnable r2 = new Runnable(){
			@Override
			public void run(){
				try {
					for(Integer s:keys){
						System.out.println(s);
						Thread.sleep(1000);
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};
		
		Thread t1 = new Thread(r1);
		Thread t2 = new Thread(r2);
		
		t1.start();
		t2.start();
	}


Hashtable是线程安全的,产生这个结果说明得到的Set集合与原有Map存在某种耦合,翻阅代码查到了这里,也恍然回想起文章开头提到的那个问题。

出现这个错误属于大意被经验所欺骗,如果基础知识够夯实也不会写出这样憋足的代码。

那么,除去Hashtable,HashMap与TreeMap的keySet方法也是遵从了相同的原则,它们均使用内部Set类型,直接或间接地使用自身Map实例进行Set构造,这也就意味着对此类Set集合的操作要加倍小心。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值