一个异常引发的集合多线程思考

原创 2015年11月17日 21:04:51

  对于Hashtable和HashMap,相信每个学习Java的人都不会陌生,这两个集合在用法上并没有什么不同,但在使用环境上却有很大差别:

1)区别,这两个类主要有以下几方面的不同:
      HashtableHashMap都实现了Map接口,但是Hashtable的实现是基于Dictionary抽象类
      在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null 
      当get()方法返回null值时,即可以表示 HashMap中没有该键,也可以表示该键所对应的值为null
      因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键,而应该用containsKey()方法来判断。
      而在Hashtable中,无论是key还是value都不能为null
 
 这两个类最大的不同在于:
1Hashtable是线程安全的,它的方法是同步了的,可以直接用在多线程环境中。
2)而HashMap则不是线程安全的。在多线程环境中,需要手动实现同步机制。

     上面所提的是面试官非常热衷提问的(当然有水平的公司也会问的更深,比如HashMap的实现机制),但这并非今天要说的重点。

     本人学习Java语言多年,自认对这两个类了如指掌,可是一次变成过程中所遇到的异常,让我发现自己对这两个类的理解还不够深入。

     前段时间,本人使用Java语言实现了一个时间调度算法,这个算法是本人一片论文中的,该算法涉及多线程,所以我理所应当的用到了HashTable,但在测试阶段却频繁的跳出一个异常,ConcurrentModificationException,虽然很快得到了很好的解决,但这个异常,使我对HashMap,Hashtable,ConcurrentHashMap有了一个更深层的认识。

     首先,很多人都知道,多线程情况下应该使用HashTable,或是使用CollectionsSynchronizedMap对HashMap进行同步。但看似同步的Map却仍然存在潜在的线程安全问题,可以考虑下面一种场景

如下面这段代码:
Java代码

<pre class="java" name="code"><span style="font-size:18px;">// shm是SynchronizedMap的一个实例   
    if(shm.containsKey('key')){   
        shm.remove(key);   
       }  
</span>


   这段代码用于从map中删除一个元素之前判断是否存在这个元素。这里的containsKeyreomve方法都是同步的,但是整段代码却不是。为什么?假设:线程A执行了containsKey方法返回true,准备执行remove操作;这时另一个线程B开始执行,同样执行了containsKey方法返回true,并接着执行了remove操作;然后线程A接着执行remove操作时发现此时已经没有这个元素了。这时就会抛出上面我所遇到的异常ConcurrentModificationException,要保证这段代码按我们的意愿工作,一个办法就是对这段代码进行同步控制,但是这么做付出的代价太大。

    我算法中所遇到的异常产生于迭代过程中,代码如下:

    

<span style="font-size:18px;"> Iterator keys = map.keySet().iterator();   
   while(keys.hasNext()){   
        map.get(keys.next());   
      }  
  </span>

     碰到这个异常的时候我也百思不解,明明是线程安全的怎么会产生这个异常,原来得到的keySet和迭代器都是Map中元素的一个视图,而不是副本问题也就出现在这里,当一个线程正在迭代Map中的元素时,另一个线程可能正在修改其中的元素。此时,在迭代元素时就可能会抛出 ConcurrentModificationException异常。

   意识到问题的所在,那解决起来也容易多了,最后我使用了ConcurrentHashMap做了替换。

    ConcurrentHashMap提供了和Hashtable以及SynchronizedMap中所不同的锁机制。Hashtable中采用的锁机制是一次锁住整个hash表,从而同一时刻只能由一个线程对其进行操作;ConcurrentHashMap中则是一次锁住一个桶。     

    ConcurrentHashMap默认将hash表分为16个桶,诸如get,put,remove等常用操作只锁当前需要用到的桶。这样,原来只能一个线程进入,现在却能同时有16个写线程执行,并发性能的提升是显而易见的。 
    在迭代方面,ConcurrentHashMap使用了一种不同的迭代方式。
    在这种迭代方式中,当iterator被创建后集合再发生改变就不再是抛出ConcurrentModificationException 取而代之的是  在改变时new新的数据从而不影响原有的数据 iterator完成后再将头指针替换为新的数据这样iterator线程可以使用原来老的数据。而写线程也可以并发的完成改变。

  至此,问题解决,同时,对于集合的多线程又有了一个新的了解,所以以后多线程还是用ConcurrentHashMap比较好!!!




 

java多线程(十)使用线程安全的集合

在多线程中,如果要并发的修改一个数据结构,那么很有可能会破坏这个数据结构。例如,一个线程可能要向一个散列表中插入一个元素,假如在调整各个桶之间的链接关系时被剥夺了控制权,而此时正好有另外一个线程正在遍...
  • xingjiarong
  • xingjiarong
  • 2015年08月29日 08:52
  • 9592

Java多线程-并发中的集合详解

参考:http://www.cnblogs.com/dolphin0520/p/3938914.html 多线程并发中的集合 一、Map 1、ConcurrentHashMap (1) 对HashTa...
  • Love_JavaProgram
  • Love_JavaProgram
  • 2015年12月27日 19:28
  • 1804

java基础复习(集合、泛型、IO流、多线程、Junit 、内省 、Properties、 路径问题)

集合---|Collection: 单列集合 ---|List: 有存储顺序, 可重复 ---|ArrayList: 数组实现, 查找快, 增删慢 ...
  • guanhang89
  • guanhang89
  • 2016年04月25日 11:29
  • 4282

多线程集合队列等等

对于许多线程问题,可以通过使用一个或多个队列以优雅且安全的方式将其形式化。当试图向队列添加元素而队列已满,或是想从队列移出元素而队列为空的时候, 阻塞队列( blocking queue)导致线程阻塞...
  • u014034934
  • u014034934
  • 2017年01月23日 14:51
  • 433

多线程处理一个list的集合

import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable;...
  • johnjobs
  • johnjobs
  • 2015年05月13日 10:26
  • 2833

Java基础总结(二)----集合、多线程、io、虚拟机等

Java集合java集合框架的结构List接口List接口通常表示一个列表(数组、队列、链表、栈等),其中的元素可以重复,常用实现类为ArrayList和LinkedList,另外还有不常用的Vect...
  • wgyscsf
  • wgyscsf
  • 2017年04月04日 22:32
  • 1688

多线程操作集合时如何保证集合的线程安全性

using System;   using System.Collections.Generic;   using System.Threading;       namespace Coll...
  • q1512451239
  • q1512451239
  • 2017年03月23日 20:05
  • 227

java基础知识(六)——异常、IO流、多线程、反射、集合

java基础知识(六)——异常、IO流、多线程、反射、集合 1、异常:
  • lvkemitu
  • lvkemitu
  • 2016年08月22日 11:26
  • 298

集合划分问题

转载请注明出处 http://blog.csdn.net/pony_maggie/article/details/18048599 作者:小马 思考下面一个问题, 给定正整数n...
  • pony_maggie
  • pony_maggie
  • 2014年07月12日 22:21
  • 4501

Java多线程中的阻塞队列和并发集合

本章主要探讨在多线程程序中与集合相关的内容。在多线程程序中,如果使用普通集合往往会造成数据错误,甚至造成程序崩溃。Java为多线程专门提供了特有的线程安全的集合类,通过下面的学习,您需要掌握这些集合的...
  • royal007a
  • royal007a
  • 2015年06月14日 17:41
  • 1620
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:一个异常引发的集合多线程思考
举报原因:
原因补充:

(最多只允许输入30个字)