Java-depth study 07: ConcurrentModificationException abnormal and CopyOnWriteArrayList

Java-depth study 07: ConcurrentModificationException abnormal and CopyOnWriteArrayList

First, look at a single thread read Iterator traversal abnormal

1- code is as follows: Create a ArrayList, and add three elements; open a thread, traverses the ArrayList, while reading the data, while deleting data

public class CopyOnWriteArrayListTest {
    public static void main(String[] args) {
        CopyOnWriteArrayListThread t  = new CopyOnWriteArrayListThread();
        for(int i = 0; i< 1; i++){
            new  Thread(t).start();
        }
    }
}

class CopyOnWriteArrayListThread implements  Runnable{
    //方式1
    public static List<String> list = new ArrayList<String>();

    static{
        list.add("AA");
        list.add("BB");
        list.add("CC");
    }


    @Override
    public void run() {
        Iterator<String> iterator = list.iterator();
        while(iterator.hasNext()){
            String str = iterator.next();
            System.out.println(str);

            if(str.equals("CC")){
                list.remove(str);
            }
        }
    }
}

 

2- The results are as follows: Exception Report ConcurrentModificationException

java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    at java.util.ArrayList$Itr.next(ArrayList.java:851)
    at juc.concurrentmap.CopyOnWriteArrayListThread.run(CopyOnWriteArrayListTest.java:42)
    at java.lang.Thread.run(Thread.java:748)

 

3- Causes ConcurrentModificationException abnormality;

  When performing iterator.next () method, we will carry out internal checkForComodification () judgment, when they throw ConcurrentModificationException modCount = expectedModCount when abnormal!;

  Wherein when the number of times ModCount ArrayList modified record, modify expectations expectedModCount ArrayList number is, its initial value ModCount;

   list.remove within (str) operation performed modCount ++; however expectedModCount and the amount of rice is updated, so the error;

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];
}

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

 4 the single-threaded solution: change list.remove (str) is iterator.remove (); ArrayList Iterator remove method in which the updated value expectedModCount

    @Override
    public void run() {
        Iterator<String> iterator = list.iterator();
        while(iterator.hasNext()){
            String str = iterator.next();
            System.out.println(str);

            if(str.equals("CC")){
                iterator.remove();
            }
        }
    }

 

private class Itr implements Iterator<E> {
    //ArrayList中Iterator的remove方法
     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();
            }
        }    
}       

 


 

Second, multithreaded, even if iterator.remove (); still reported ConcurrentModificationException;

1- code is as follows: Create a ArrayList, and add three elements; open 10 threads, traverse the ArrayList, while reading the data, while deleting data

public class CopyOnWriteArrayListTest {
    public static void main(String[] args) {
        CopyOnWriteArrayListThread t  = new CopyOnWriteArrayListThread();
        for(int i = 0; i< 10; i++){
            new  Thread(t).start();
        }
    }
}

class CopyOnWriteArrayListThread implements  Runnable{
    //方式1
    public static List<String> list = new ArrayList<String>();

    static{
        list.add("AA");
        list.add("BB");
        list.add("CC");
    }

    @Override
    public void run() {
        Iterator<String> iterator = list.iterator();
        while(iterator.hasNext()){
            String str = iterator.next();
            System.out.println(str);
            if(str.equals("CC")){
                iterator.remove();
            }
        }
    }
}

 Exception log

java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    at java.util.ArrayList$Itr.next(ArrayList.java:851)
    at juc.concurrentmap.CopyOnWriteArrayListThread.run(CopyOnWriteArrayListTest.java:46)
    at java.lang.Thread.run(Thread.java:748)

! 2- analysis of the problem: the reason is still modCount = expectedModCount cause; so to understand modCount parameters belong to the object list, namely 10 threads a public modCount; but expectedModCount belong Iterator object list, and the list of Iterator objects in each new thread , recreated; the expectedModCount each thread are independent of each other, it will inevitably lead to "public variable" modCount not equal to the expectedModCount.

3- Solution: Use CopyOnWriteArrayList recording list data, and the data is removed using list.remove (str);

class CopyOnWriteArrayListThread implements  Runnable{
    //方式2
    public static CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();

    static{
        list.add("AA");
        list.add("BB");
        list.add("CC");
    }

    @Override
    public void run() {
        Iterator<String> iterator = list.iterator();
        while(iterator.hasNext()){
            String str = iterator.next();
            System.out.println(str);
            if(str.equals("CC")){
                list.remove(str);
            }
        }
    }
}

 


 

Third, the CopyOnWriteArrayList

What 1-CopyOnWriteArrayList that?

  According to the official notes: CopyOnWriteArrayList is thread-safe ArrayList, their corresponding add, remove and other modification operations will also create a new copy

How do thread-safe 2-CopyOnWriteArrayList

  add () and remove (): CopyOnWriteArrayList class greatest feature is, after the operation to modify (add / remove, etc.) and creates a new modification data, examples thereof modification is completed, then the original reference point to the new array. Thus, the modification process does not modify the original array. There will be no ConcurrentModificationException error.

    //CopyOnWriteArrayList中的add方法
    public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }
     //CopyOnWriteArrayList中的remove方法,调用下面的 remove(o, snapshot, index)
    public boolean remove(Object o) {
        Object[] snapshot = getArray();
        int index = indexOf(o, snapshot, 0, snapshot.length);
        return (index < 0) ? false : remove(o, snapshot, index);
    }
     //真正的remove方法
    private boolean remove(Object o, Object[] snapshot, int index) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] current = getArray();
            int len = current.length;
            if (snapshot != current) findIndex: {
                int prefix = Math.min(index, len);
                for (int i = 0; i < prefix; i++) {
                    if (current[i] != snapshot[i] && eq(o, current[i])) {
                        index = i;
                        break findIndex;
                    }
                }
                if (index >= len)
                    return false;
                if (current[index] == o)
                    break findIndex;
                index = indexOf(o, current, index, len);
                if (index < 0)
                    return false;
            }
            Object[] newElements = new Object[len - 1];
            System.arraycopy(current, 0, newElements, 0, index);
            System.arraycopy(current, index + 1,
                             newElements, index,
                             len - index - 1);
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

 

get()

        //CopyOnWriteArrayList中的get方法
      public E get(int index) {
            final ReentrantLock lock = l.lock;
            lock.lock();
            try {
                rangeCheck(index);
                checkForComodification();
                return l.get(index+offset);
            } finally {
                lock.unlock();
            }
        }    

 

Guess you like

Origin www.cnblogs.com/wobuchifanqie/p/12510537.html
Recommended