@lzb1096101803
2016-03-05T09:57:06.000000Z
字数 1249
阅读 513
电话面试
http://blog.csdn.net/shohokuf/article/details/3932967
Hashtable 继承自 Dictiionary 而 HashMap继承自AbstractMap
Hashtable的put方法:
注意1 方法是同步的
注意2 方法不允许value==null
注意3 方法调用了key的hashCode方法,如果key==null,会抛出空指针异常
线程安全的,单线程环境下它比HashMap要慢
HashMap的put方法:
注意1 方法是非同步的
注意2 方法允许key==null
注意3 方法并没有对value进行任何调用,所以允许为null
非线程安全的,ConcurrentHashMap替代Hashtable
HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。
HashMap可以通过下面的语句进行同步:
Map m = Collections.synchronizeMap(hashMap);
补充:
Hashtable 有一个 contains方法,容易引起误会,所以在HashMap里面已经去掉了
当然,2个类都用containsKey和containsValue方法。
哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。
Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。
java.util包下面的所有的集合类都是快速失败的,而java.util.concurrent包下面的所有的类都是安全失败的。快速失败的迭代器会抛出ConcurrentModificationException异常,而安全失败的迭代器永远不会抛出这样的异常
Iterator的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响。
fail-fast解决办法
使用CopyOnWriteArrayList来替换ArrayList
?ArrayList 的一个线程安全的变体,其中所有可变操作(add、set 等等)都是通过对底层数组进行一次新的复制来实现的。 该类产生的开销比较大,但是在两种情况下,它非常适合使用。
1:在不能或不想进行同步遍历,但又需要从并发线程中排除冲突时。
2:当遍历操作的数量大大超过可变操作的数量时。