Fail-Fast和Fail-safe

什么是Fail-Fast

  • 在多线程环境下,线程A在进行遍历时,如果线程B修改了集合中的内容,线程A在遍历时会抛出并发修改异常
  • 同时也出现在单线程环境中,线程在遍历的过程中同时对集合中的内容进行了修改,此时也会抛出并发修改异常
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
    String tmp = iter.next();
    System.out.println(tmp);
    if (tmp.equals("1")) {
        list.remove("1");
    }
}
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
    String tmp = iter.next();
    System.out.println(tmp);
    if (tmp.equals("2")) {
        list.remove("2");
    }
}
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
    String tmp = iter.next();
    System.out.println(tmp);
    if (tmp.equals("2")) {
        list.remove("2");
    }
}
List<String> list = Arrays.asList("1", "2", "3", "4");
for (String i : list) {
    if ("1".equals(i)) {
        list.remove("1");
    }
}
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
    String tmp = iter.next();
    System.out.println(tmp);
    if (tmp.equals("1")) {
        iter.remove("1");
    }
}
  • 在代码块13中,会抛出并发修改异常 **ConcurrentModificationException**
Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:911)
	at java.util.ArrayList$Itr.next(ArrayList.java:861)
	at com.example.homework.controller.Client.main(Client.java:23)
  • 代码块4中,会抛出异常** ****UnsupportedOperationException**

为什么代码块13抛出异常

  • **ArrayList**中的使用的迭代器的**Next**方法在内部类Itr中
  • 在迭代器**next**方法中,会调用 **checkForComodification**
  • **modCount != expectedModCount**时,就会抛出**ConcurrentModificationException**
  • **modCount**记录的是**操作次数**,在**ArrayList**方法中,**add****remove**方法会使**modCount+1**,set方法不会操作modCount
  • 因为**expectedModCount**是在**创建迭代器时**初始化赋值,使用**ArrayList****remove**方法不会修改**expectedModCount**,因此在代码块13中会因为**modCount****expectedModCount**不相等而抛出异常
private class Itr implements Iterator<E> {
    int cursor;       // index of next element to return
    int lastRet = -1; // index of last element returned; -1 if no such
    int expectedModCount = modCount;

    Itr() {}

    public boolean hasNext() {
        return cursor != size;
    }

    @SuppressWarnings("unchecked")
    public E next() {
        checkForComodification();
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }

    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            ArrayList.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }

    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

为什么代码块2不抛出异常

  • 在迭代器循环中会使用**hasNext**方法判断是否含有下一个元素,判断条件是**cursor != size **
  • 在代码块2中在调用**ArrayList.remove**方法后,删除了该元素,此时集合会size-1
  • **cursor**属性代表中**next方法要访问的元素的下标**,代码块2中此时遍历到**倒数第二个元素**,因为此时size-1后,此时**cursor和size相等**,迭代器会判断已经遍历到集合的末尾,从而退出循环。
  • 此时不会访问到集合末尾的元素,也就没**有再调用末尾的next**方法,因此也就**不会抛出对应的异常**

为什么代码块4抛出异常

  • 代码块4中的集合不是java.util包下的ArrayList,这个是Arrays工具类中一个**内部类ArrayList**
  • 他的元素集合定义为**final**,并且该类**没有重写** add、remove等方法,在 AbstractList 的默认实现中会抛出对应的异常
public void add(int index, E element) {
    throw new UnsupportedOperationException();
}

为什么代码块5不会抛出异常

  • 代码块5使用的是迭代器进行元素的删除
  • 在迭代器的元素删除中,会先调用**ArrayList****remove**方法,然后再将新的**modCount**值赋值给 **expectedModCount**
  • 因为迭代器中的 可以**实时更新**,因此不会因为**modCount****expectedModCount**不相等而抛出异常
public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

Fail-safe

copyOnWriteArrayList
没有设计抛出并发修改异常的代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值