`
IXHONG
  • 浏览: 446239 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

【转载】ArrayList 中数据删除 & fail fast

阅读更多

本文转载自http://shift-alt-ctrl.iteye.com/blog/1839147

 

在循环arrayLlist时,经常会遇到remove操作,那么arrayList的remove的底层是怎么做的?

AbstractList中,有一个属性modCount,这个属性是跟踪list中数据被修改的次数,任何对list的add/remove操作,都将导致modCount++.

在AbstractList中还有一个内部类Itr implements Iterator,Itr是一个list遍历的工具类,当然list.iterator()方法也是返回Itr对象,在Itr中有一个校验位属性expectedModCount;对于一个itr对象,其初始时expectedModCount=modCount.

Iterator是list一个视图,其最终还是操作list的存储结构.在使用iterator遍历时,remove()操作,会导致modCount++(AbstractList.remove()),但是还有expectedModCount=modCount,即在iterator中remove数据,会带来expectedModCount与modCount值的同步.

在Iterator遍历时,next(),remove()方法会校验expectedModCount与modCount值是否一致,如果不一致,就意味着这list数据在iterator外部被修改,此时iterator遍历将会造成ConcurrentModificationException.

 

AbstractLlist不仅支持普通的iterator,还支持ListIterator(ArrayList,LinkedList均支持),ListIterator增加了遍历时双向游标能力(previous,next),增加了add方法.add方法和remove方法一样也做了expectedModCount和modCount一致性校验.

 引申一下,如下四个对list数据删除的代码,有区别吗??

如下是4中循环方式:

1) for(int i=0;i<list.size();i++){

list.remove(i);

}

2) for(int i=list.size()-1;i>=0;i--){

list.remove(i);

}

3)

int size = list.size();

for(int i=size-1;i>-1;i--){

list.remove(i);

}

 

4) for(Object i : list){

list.remove(i);//如果list中存在多个Object互相equals时,此方法仍然有效.注意list.remove(Object)内部使用了遍历操作,并使用equals来比较对象并删除.

}

5) Iterator it = list.iterator()

while(it.hasNext()){

it.next();

it.remove();

}

 

1),2),3)是最普通的遍历方式,但是在遍历并有删除操作时,似乎它们执行的结果还有些差距,根据坐标删除,那么1)实事上只会有一半被删掉,1)中每删除一次,计算一次list.size(),但是当前i++,且前端删除会造成数组结构copy.

2)后端删除,不会造成copy,每次都是删除最后一个位置,直至结束

3)因为size没有重新计算,在删除一半数据后,抛出IndexOutOfBoundsException

4)/5)正常

 

提示:foreach方式最终是转换成了iterator的方式进行.(产生于编译过程中).

 

关于fail fast:

在并发的时候,如果线程A正遍历一个collection(List, Map, Set etc.),这时另外一个线程B却修改了该collectionsize,线程A就会抛出一个错:ConcurrentModificationException,表明:我正读取的内容被修改掉了,你是否需要重新遍历?或是做其它处理?这就是fail-fast的含义。

 

Fail-fast是并发中乐观(optimistic)策略的具体应用,它允许线程自由竞争,但在出现冲突的情况下假设你能应对,即你能判断出问题何在,并且给出解决办法。悲观(pessimistic)策略就正好相反,它总是预先设置足够的限制,通常是采用锁(lock),来保证程序进行过程中的无错,付出的代价是其它线程的等待开销: 

 

Doug Leaconcurrent包给出了另外一种解决方案,Copy On Write。它的CopyOnWriteArrayListCopyOnWriteArraySet会在线程B试图修改数据容器时,给出一个copy出来的容器(当然,我们程序中是感觉不到的),这样线程A在老版本的v上遍历,线程B则在新版本的v上修改,两者互不相干,也决不会出现ConcurrentModificationException。它的代价则主要是在容器的copy上,当并发程度越高,其开销也越高。

 

 

所以,Fast Fail被引入JDK的一个基本前提是:你绝大多数的情形,仅仅是在遍历一个collection,不会有另外的线程会对它做update。如此,它的效率是最充分的。但如果你不断遇到ConcurrentModificationException的异常时,则要考虑是否要进行一定次数的重新遍历,或者干脆采用悲观策略锁住资源来保证线程安全。

分享到:
评论

相关推荐

    Java Collections中的Fail Fast机制

    ### Java Collections中的Fail Fast机制详解 #### 一、概述 在Java编程中,**Fail Fast**机制是一项重要的设计原则,特别是在处理集合时尤为关键。它主要用于确保数据结构的一致性和完整性,通过快速检测并报告...

    ArrayList数据批量添加数据

    本篇文章将详细介绍如何利用`ArrayList`进行数据的批量添加,并通过一个示例来展示如何在一个事务中执行多个SQL语句。这对于需要处理大量数据并确保数据完整性的情况非常有用。 #### 一、ArrayList简介 `ArrayList...

    Arraylist 类模版

    ArrayList operator =(const ArrayList& assignArrayList); // Adds and item and returns added item. Array is resized by one. pItemType Add(pItemType anItem); // Removes the item at the given index....

    【面试普通人VS高手系列】Fail-safe机制与Fail-fast机制分别有什么作用.doc

    这种机制下的集合容器,例如HashMap和ArrayList等,都是java.util包下的集合类,它们在遍历时直接访问集合内容,因此在遍历过程中对集合数据做变更时,就会发生Fail-fast。 Fail-safe机制是一种失败安全机制,在...

    ArrayList动态删除 自定义Adapter (附源码)

    ArrayList动态删除与自定义Adapter是Android开发中的常见操作,它涉及到数据存储、用户界面更新以及适配器模式的运用。在Android中,ListView是展示大量数据的常用组件,而ArrayList作为Java集合框架的一部分,通常...

    老生常谈java中的fail-fast机制

    在Java的Collection框架中,包括ArrayList、HashMap等集合类都支持Fail-Fast机制。例如,在ArrayList中,当迭代器在遍历ArrayList时,如果另一个线程修改了ArrayList的结构,迭代器将抛出...

    day09-ArrayList集合&学生管理系统.pdf

    ### ArrayList集合简介 ArrayList是Java集合框架中的重要部分,是一种能够存储可变数量元素的集合。...此外,使用泛型来约束集合中的数据类型是提高代码安全性的关键步骤,需要在定义ArrayList时指定具体的数据类型。

    day07 15 ArrayList集合存储基本数据类型

    day07_15_ArrayList集合存储基本数据类型

    ListView显示单列ArrayList_demo

    标题 "ListView 显示单列 ArrayList_demo" 表明,这个示例程序的目的是展示如何使用 ArrayList 将数据显示在 ListView 中。 描述解释 描述 "ListView 显示单列 ArrayList_demo" 也是对标题的进一步解释,表明这个...

    c#数据结构之array,arraylist,hashtable,dictionary

    C#中有多种数据结构可以用来存储和管理数据,今天我们将讨论四种常用的数据结构:Array、ArrayList、Hashtable和Dictionary。这些数据结构都是_Collections_命名空间的一部分,提供了不同的方式来存储和检索数据。 ...

    JNI与C++数据类型传递示例(包括ArrayList对象、ArrayList嵌套返回)

    一个C++(Ubuntu16.04+QT5.9.1)通过JNI,调用JAVA类及方法的示例。通过JNI传递和返回多种类型的参数,boolean ,int,String,ArrayList,ArrayList嵌套ArrayList&lt;ArrayList&lt;String&gt;&gt;等。

    jni操作arraylist对象

    在这个主题中,我们将深入探讨如何在JNI中操作ArrayList对象并添加一个int类型的数据。 首先,我们需要理解ArrayList在Java中的本质。ArrayList是Java集合框架中的一个重要类,它实现了List接口,用于存储可变大小...

    C#160使用对象ArrayList填充DataGrid 源代码

    为了将ArrayList中的数据填充到DataGrid,我们需要创建一个DataTable并映射到ArrayList中的对象,因为DataGrid默认使用DataTable作为数据源: ```csharp DataTable dataTable = new DataTable(); dataTable.Columns...

    ArrayList转化为DataTable

    在.NET框架中,ArrayList和DataTable是两种常用的集合类,它们分别代表了两种不同的数据存储方式。ArrayList是一个基于对象数组的动态大小的列表,而DataTable则是一个内存中的表格数据结构,通常用于存储和操作关系...

    使用对象ArrayList填充DataGrid,C#源代码ArrayList MyList = new ArrayList();

    需要注意的是,由于ArrayList没有内置的类型安全,所以在使用DataGrid显示ArrayList中的复杂对象(如Person)时,需要指定DataGrid的数据成员(DataMember),以及各列的映射名(MappingName)。这样,DataGrid才能...

    集合ArrayList测试集合ArrayList测试集合ArrayList测试

    在实际应用中,选择`ArrayList`还是其他集合类型,如`LinkedList`或`HashSet`,应根据具体需求来决定,例如是否需要保持元素顺序、是否频繁进行插入和删除、是否需要线程安全等。 总结来说,`ArrayList`是Java集合...

Global site tag (gtag.js) - Google Analytics