引言
前几天刷视频,看到一位程序员好像叫”建国“,他写了一段代码,不出意外,这位叫”建国“的同学又要挨批了。
ArrayList<Integer> list1=new ArrayList<>();
for (int i = 0; i < 10; i++) {
list1.add(i);
}
Iterator<Integer> iterator = list1.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
if (iterator.next()==3)
{
list1.remove(0);
}
}
这段代码开始没有什么违和感,但是在多线程情况下就会抛出Concurrent Modification Exception。也就是fail-fast。
fail-fast
原因:用迭代器遍历集合石,线程a遍历过程中,线程b对集合对象内容进行了增删,会抛出Concurrent Modification Exception。
原理:集合在遍历期间会检测expectedmodCount与modCount的值是否相等,相同的话就继续遍历,否则抛出异常。java.util 包下的集合类都是快速失败的,不能在多线程下发生并发修改(迭代过程中被修改),比如 ArrayList 类。
例如以下多线程场景。
package udpDemo; import java.util.ArrayList; import java.util.Iterator; import java.util.concurrent.CopyOnWriteArrayList; public class demo1 { static ArrayList<Integer> list1=new ArrayList<>(); public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 10; i++) { list1.add(i); } t1 t1 = new t1(); t2 t2 = new t2(); Thread thread1 = new Thread(t1); Thread thread2 = new Thread(t2); thread2.start(); thread1.start(); Thread.sleep(3000); System.out.println("list1的大小"+list1.size()); } public static class t1 implements Runnable{ @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } for (int i = 0; i < 10; i++) { if (list1.get(i)==5) { list1.remove(4); } } } } public static class t2 implements Runnable{ @Override public void run() { Iterator<Integer> iterator = list1.iterator(); int a=0; while (iterator.hasNext()) { try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } a++; System.out.println(iterator.next()); } System.out.println("迭代器输出了"+a+"次"); } } }会抛出以下异常
![]()
解决方案:使用CopyOnWitreArrayList
CopyOnWriteArrayList 采用了一种读写分离的并发策略。CopyOnWriteArrayList 容器允许并发读,读操作是无锁的,性能较高。至于写操作,比如向容器中添加一个元素,则首先将当前容器复制一份,然后在新副本上执行写操作,结束之后再将原容器的引用指向新容器。
fail-safe
原理:遍历时不直接在结合内容上访问,先复制原集合内容,遍历拷贝的集合。所以不会触发 Concurrent Modification Exception
缺点:修改原集合,迭代器是不会发现的。
java.util.concurrent 包下的容器都是安全失败,可以在多线程下并发使用,并发修改,比如 CopyOnWriteArrayList 类。
例如下面的多线程场景:
package udpDemo; import java.util.ArrayList; import java.util.Iterator; import java.util.concurrent.CopyOnWriteArrayList; public class demo1 { static CopyOnWriteArrayList<Integer> list1 = new CopyOnWriteArrayList<>(); public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 10; i++) { list1.add(i); } t1 t1 = new t1(); t2 t2 = new t2(); Thread thread1 = new Thread(t1); Thread thread2 = new Thread(t2); thread2.start(); thread1.start(); Thread.sleep(3000); System.out.println("list1的大小"+list1.size()); } public static class t1 implements Runnable{ @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } for (int i = 0; i < 10; i++) { if (list1.get(i)==5) { list1.remove(4); } } } } public static class t2 implements Runnable{ @Override public void run() { Iterator<Integer> iterator = list1.iterator(); int a=0; while (iterator.hasNext()) { try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } a++; System.out.println(iterator.next()); } System.out.println("迭代器输出了"+a+"次"); } } }查看控制台

673

被折叠的 条评论
为什么被折叠?



