博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
fail-fast与fail-safe在Java集合中的应用
阅读量:5807 次
发布时间:2019-06-18

本文共 2607 字,大约阅读时间需要 8 分钟。

fail-fast与fail-safe简介

如果一个系统,当有异常或者错误发生时就立即中断执行,这种设计称之为fail-fast。相反如果我们的系统可以在某种异常或者错误发生时继续执行,不会被中断,这种设计称之为fail-safe

fail-fast与fail-safe在Java迭代器中的设计

在Java中,最典型的fail-fast与fail-safe就是关于迭代器的设计。通常情况下,那些线程不安全的集合类产生的迭代器都是fail-fast的,而线程安全的集合类产生的迭代器是fail-safe的。fail-fast的迭代器会在迭代过程中,如果你修改了集合类里的内容,则会抛出ConcurrentModificationException异常。fail-safe的迭代器则可以在迭代过程中任意修改集合类的内容,不会有异常抛出。

Java的fail-fast迭代器

前面说过,线程安全的集合类产生的迭代器是基于fail-fast设计的,例如ArrayList。这种迭代器迭代过程中是直接访问原数据信息的,所以当原集合内容修改了后,迭代器不能保证正确的迭代过程。代码示例如下:

public static void failFast() {        List
list = new ArrayList<>(); list.add("item-1"); list.add("item-2"); list.add("item-3"); list.add("item-4"); Iterator
it = list.iterator(); while (it.hasNext()) { String item = it.next(); System.out.println(item); list.add("itme-5"); // 下次迭代时会抛出ConcurrentModificationException异常 } }

通过分析ArrayList源码可以看出,当对ArrayList做添加或者删除元素的操作时,都会修改modCount这个变量,而ArrayList的迭代器每次迭代的时候,又都回去检查当前modCount和迭代器产生时的expectedModCount变量是否相等,如果不等就会抛出ConcurrentModificationException异常。

protected transient int modCount = 0;public boolean add(E e) {    ensureCapacityInternal(size + 1);  // Increments modCount!!    // 上面那个方法调用后会修改modCount    ....}// ArrayList的迭代器private class Itr implements Iterator
{ public E next() { checkForComodification(); ... } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } ...}

Java的fail-safe迭代器

对于那些线程安全的集合类,在调用iterator方法产生迭代器的时候,会将当前集合的素有元素都做一个快照,即复制一份副本。每次迭代的时候都是访问这个快照内的元素,而不是原集合的元素。代码示例如下:

public static void failSafe() {        List
list = new CopyOnWriteArrayList<>(); list.add("item-1"); list.add("item-2"); list.add("item-3"); list.add("item-4"); Iterator
it = list.iterator(); while (it.hasNext()) { String item = it.next(); System.out.println(item); list.add("itme-5"); } System.out.println(list.size()); // 会打印出来8,迭代四次,四个新元素插入到了集合中。 }

这种设计的好处是保证了在多线程操纵同一个集合的时候,不会因为某个线程修改了集合,而影响其他正在迭代访问集合的线程。缺点是,迭代器不能正确及时的反应集合中的内容,而且一定程度上也增加了内存的消耗。

迭代器小提示

如果用Java的for loop来访问集合,原理上还是用迭代器的方式,所以下面的代码同样会抛出ConcurrentModificationException异常。

List
list = new ArrayList<>(); list.add("item-1"); list.add("item-2"); list.add("item-3"); list.add("item-4"); for (String item : list) { System.err.println(item); list.add("itme-5"); }

转载地址:http://mqubx.baihongyu.com/

你可能感兴趣的文章
Java 07 example
查看>>
RF框架搭建
查看>>
Redis 与 数据库处理数据的两种模式
查看>>
SQL语句关联查询
查看>>
python学习 day4
查看>>
Ubuntu 下安装Kibana和logstash
查看>>
js在mootools框架下的new Class
查看>>
Oracle select case when
查看>>
matlab print,disp,fprint,fscan
查看>>
Remove Nth Node From End of List
查看>>
301重定向与302跳转有什么区别?
查看>>
类似于Mimikatz的Linux Hash Dump工具
查看>>
CORS协议与Spring注解的冲突
查看>>
nginx fastcgi负载均衡
查看>>
Innodb之线程独享内存
查看>>
Android+Eclipse+Java:在“正在启动 CrazySnake”期间发生了内部错误, java.lang.NullPointerException...
查看>>
本地远程访问服务器jupyter
查看>>
anaconda下jieba和wordcloud安装
查看>>
57.6174问题
查看>>
大专生自学Java到找到工作的经历
查看>>