快速失败Vs安全失败(Java迭代器附示例)

译者:java达人-卍极客

英文出处:Java Concept Of The Day

英文链接:http://javaconceptoftheday.com/(点击文末阅读原文前往)

转载请标注以上声明

简介:

当错误发生时,如果系统立即关闭,即是快速失败,系统不会继续运行。运行中发生错误,它会立即停止操作,错误也会立即暴露。而安全失败系统在错误发生时不会停止运行。它们隐蔽错误,继续运行,而不会暴露错误。这两种模式,孰优孰优,是系统设计中常讨论的话题,在此,我们只讨论java中的快速失败和安全失败迭代器。

Java快速失败与安全失败迭代器 :

java迭代器提供了遍历集合对象的功能,集合返回的迭代器有快速失败型的也有安全失败型的,快速失败迭代器在迭代时如果集合类被修改,立即抛出ConcurrentModificationException异常,而安全失败迭代器不会抛出异常,因为它是在集合类的克隆对象上操作的。我们来看看快速失败和 安全失败迭代器的具体细节。

java快速失败迭代器 :

大多数集合类返回的快速失败迭代器在遍历时不允许结构性修改(结构性修改指添加,删除和更新一个元素) 当遍历的同时被结构性修改,就会抛出ConcurrentModificationException异常,而当集合是被迭代器自带的方法(如remove())修改时,不会抛出异常。

快速失败迭代器运行原理:

所有的集合类都维护着一个对象数组(Object[]),用来存储元素, 快速失败迭代器直接从数组中获取元素,在迭代过程中,总是假定该内部数组不会被修改。为了判断这个集合是否被修改,它们使用名为modCount的内部标识,当集合被修改,该标识也会更新。迭代器每次调用next()方法,都会检查modCount,如果发现modCount被更新,就会抛出ConcurrentModificationException异常。

ArrayList,Vector,HashMap等集合返回的迭代器都是快速失败类型的。

import java.util.ArrayList;
import java.util.Iterator;
public class FailFastIteratorExample 
{       
    public static void main(String[] args) 
    {
        //Creating an ArrayList of integers
        ArrayList<Integer> list = new ArrayList<Integer>();
        //Adding elements to list
        list.add(1452);
        list.add(6854);
        list.add(8741);
        list.add(6542);
        list.add(3845);
        //Getting an Iterator from list
        Iterator<Integer> it = list.iterator();
        while (it.hasNext())
        {
            Integer integer = (Integer) it.next();
            list.add(8457);      //This will throw ConcurrentModificationException
        }
    }    
}
Output :
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at pack1.MainClass.main(MainClass.java:32)

Java安全失败迭代器 :

安全失败迭代器在迭代中被修改,不会抛出任何异常,因为它是在集合的克隆对象迭代的,所以任何对原集合对象的结构性修改都会被迭代器忽略,但是这类迭代器有一些缺点,其一是它不能保证你迭代时获取的是最新数据,因为迭代器创建之后对集合的任何修改都不会在该迭代器中更新,还有一个缺点就是创建克隆对象在时间和内存上都会增加一些负担。

ConcurrentHashMap返回的迭代器是安全失败迭代器:

import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
public class FailSafeIteratorExample 
{       
    public static void main(String[] args) 
    {
        //Creating a ConcurrentHashMap
        ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();
        //Adding elements to map
        map.put("ONE", 1);
        map.put("TWO", 2);
        map.put("THREE", 3);
        map.put("FOUR", 4);
        //Getting an Iterator from map
        Iterator<String> it = map.keySet().iterator();
        while (it.hasNext())
        {
            String key = (String) it.next();
            System.out.println(key+" : "+map.get(key));
            map.put("FIVE", 5);     //This will not be reflected in the Iterator
        }
    }    
}
Output :
TWO : 2
FOUR : 4
ONE : 1
THREE : 3

快速失败迭代器

安全失败迭代器

在迭代时不允许修改集合

在迭代时允许修改集合

迭代时被修改抛出ConcurrentModificationException异常

迭代时集合被修改不抛出异常

使用原集合遍历集合元素

使用原集合的副本遍历集合元素

迭代器不要求额外的内存‍‍

‍‍迭代器需要额外的内存克隆集合对象

示例:ArrayList, Vector, HashMap

示例:ConcurrentHashMap

译者语:

总体而言是一篇好文章,就是有一个地方和javadoc有出入,即“大多数集合类返回的快速失败迭代器在遍历时不允许结构性修改(结构性修改指添加,删除和更新集合中一个元素)”这一句,而javadoc中对此的解释是“结构上的修改是指任何添加或删除一个或多个元素的操作,或者显式调整底层数组的大小;仅仅设置元素的值不是结构上的修改。” 以javadoc中的为准。

原文发布于微信公众号 - java达人(drjava)

原文发表时间:2017-01-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏青玉伏案

算法与数据结构(一) 线性表的顺序存储与链式存储(Swift版)

温故而知新,在接下来的几篇博客中,将会系统的对数据结构的相关内容进行回顾并总结。数据结构乃编程的基础呢,还是要不时拿出来翻一翻回顾一下。当然数据结构相关博客中我...

2117
来自专栏决胜机器学习

PHP数据结构(三)——运用栈实现括号匹配

PHP数据结构(三)——运用栈实现括号匹配 (原创内容,转载请注明来源,谢谢) 栈在数据结构上是一种特殊的线性表,其限制是仅允许在表的一端进行插入和删除运算,...

4246
来自专栏前端黑板报

(转)ES6新特性概览

ES6(ECMAScript 6)是即将到来的新版本JavaScript语言的标准,代号harmony(和谐之意,显然没有跟上我国的步伐,我们已经进入中国梦版本...

2115
来自专栏Lambda

Java 常见内存溢出异常与代码实现

Java 堆 OutOfMemoryError Java 堆是用来存储对象实例的, 因此如果我们不断地创建对象, 并且保证 GC Root 和创建的对象之间...

2018
来自专栏me的随笔

Python知识梳理

我们可以使用type()函数类获取对象的类型,Python3中内置数据类型包括:None,int,float,complex,str,list,dict,tup...

1362
来自专栏绿巨人专栏

TypeScript中的怪语法

1153
来自专栏光变

3.1 ASM-方法-结构

ASM-方法-结构 本章将会介绍如果使用ASM core API生成或者转换Java编译后的method。 本将开始会展示编译后的method,然后使用很多说...

1412
来自专栏我是攻城师

Apache Pig学习笔记之内置函数(三)

4274
来自专栏瓜大三哥

UVM模型(二)之component

UVM模型(二)之component Component与object是UVM中两个最重要的概念。 ? 1.uvm_component中的parent UV...

2568
来自专栏绿巨人专栏

TypeScript中的怪语法

4455

扫码关注云+社区

领取腾讯云代金券