多线程处理一个任务,报modCount、expectedModCount不一致,帮忙分析下?

package com.java.thread.lifecycle;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

/**

  • 两个线程并行处理一个任务,
  • @author Administrator
    *
    */
    public class OneTaskTwoThread {
    static char currentThread = 'A';
    static Object object = new Object();

    public static void main(String[] args) {
    List list = getList();
    Thread threadA = new Thread(new Task(object, list, currentThread), "Thread-a");
    Thread threadB = new Thread(new Task(object, list, currentThread), "Thread-b");
    threadA.start();
    threadB.start();
    }

    private static List getList() {
    List list = new ArrayList();
    for (int i = 0; i < 20; i++) {
    list.add(Integer.toString(i));
    }
    return list;
    }
    }

class Task implements Runnable {
static List list;
static char currentThread;
Object object;

public Task(Object object, List<String> list, char currentThread) {
    Task.list = list;
    Task.currentThread = currentThread;
    this.object = object;
}

@Override
public void run() {
    synchronized (object) {
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            // 打印ModCount
            // printModCount("remove before" + " curent size" + list.size(), iterator,
            // list);
            try {
                if (Thread.currentThread().getName().equals("Thread-a") && currentThread != 'A') {
                    object.wait();
                } else if (Thread.currentThread().getName().equals("Thread-b") && currentThread != 'B') {
                    object.wait();
                } else {
                    String str = iterator.next();
                    iterator.remove();

                    // 打印ModCount
                    // printModCount("remove after", iterator, list);

                    Thread.sleep(2000);
                    System.out.println(Thread.currentThread().getName() + ": remove \"" + str
                            + "\" and current size : " + list.size());
                    if (Thread.currentThread().getName().equals("Thread-a")) {
                        Task.currentThread = 'B';
                    }
                    if (Thread.currentThread().getName().equals("Thread-b")) {
                        Task.currentThread = 'A';
                    }
                    object.notifyAll();
                }
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

private void printModCount(String prefix, Iterator<String> iterator, List<String> list2) {
    System.out.println(prefix + "  : " + iterator + "  iterator expectedModCount : "
            + ReflectUtil.findDeclaredFieldValueByName(iterator, "expectedModCount") + "    ,list modCount : "
            + ReflectUtil.findDeclaredFieldValueByName(list, "modCount"));
}

}

class ReflectUtil {
/**
*
* @Description
* @date 2018年5月7日
* @author Administrator
* @return
* @Throws
*/
public static Field[] findAllDeclaredFields(Object obj) {
Class<? extends Object> clazz = obj.getClass();
Field[] fields = new Field[0];
fields = findDeclaredFields(clazz, fields);
return fields;
}

private static Field[] findDeclaredFields(Class<? extends Object> clazz, Field[] fields) {
    // 查找当前类中的属性
    Field[] tempFields = clazz.getDeclaredFields();
    // 合并tempFields到fields
    int oldLen = fields.length;
    // Arrays.copyOf产生了新的fields数组,最后要return出去
    fields = Arrays.copyOf(fields, oldLen + tempFields.length);
    System.arraycopy(tempFields, 0, fields, oldLen, tempFields.length);
    Class<? extends Object> superClazz = clazz.getSuperclass();
    if (null != superClazz && !(superClazz == Object.class)) {
        // fields 是通过数组扩容产生的,每次扩容都是新的要重新赋值
        fields = findDeclaredFields(superClazz, fields);
    }
    // fields数组,return出去
    return fields;
}

public static Field findDeclaredFieldByName(Object obj, String name) {
    Field[] fields = ReflectUtil.findAllDeclaredFields(obj);
    Field field = null;
    for (int i = 0; i < fields.length; i++) {
        try {
            field = fields[i];
            if (field.getName().equals(name)) {
                field.setAccessible(true);
                break;
            }
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    return field;
}

public static Object findDeclaredFieldValueByName(Object obj, String name) {
    Field field = ReflectUtil.findDeclaredFieldByName(obj, name);
    Object retObj = null;
    try {
        retObj = field.get(obj);
    } catch (IllegalArgumentException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return retObj;
}

}


因为ArrayList是线程不安全的。
因此如果在使用迭代器的过程中有其他线程修改了ArrayList,那么将抛出ConcurrentModificationException,这就是所谓fail-fast策略。这一策略在源码中的实现是通过 modCount 域,modCount 顾名思义就是修改次数,对ArrayList 内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的 expectedModCount。在迭代过程中,判断 modCount 跟 expectedModCount 是否相等,如果不相等就表示已经有其他线程修改了 Map:注意到 modCount 声明为 volatile,保证线程之间修改的可见性。

因为ArrayList是线程不安全的。
因此如果在使用迭代器的过程中有其他线程修改了ArrayList,那么将抛出ConcurrentModificationException,这就是所谓fail-fast策略。这一策略在源码中的实现是通过 modCount 域,modCount 顾名思义就是修改次数,对ArrayList 内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的 expectedModCount。在迭代过程中,判断 modCount 跟 expectedModCount 是否相等,如果不相等就表示已经有其他线程修改了 ArrayList:注意到 modCount 声明为 volatile,保证线程之间修改的可见性。

集合一般都会实现自己的迭代器,ArrayList->private class ListItr extends Itr implements ListIterator
其remove 方法在 Itr实现

        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();
            }
        }

调用了 ArrayList.remove,ArrayList很多方法都只改变modCount

     public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

再看迭代器ArrayList.Itr其中的一个循环
使用迭代器是,同步了一下 expectedModCount = modCount
迭代的时候一直在判断,如果此时调用了 ArrayList.remove,modCount变化了,expectedModCount还是初始同步的值,也就
throw new ConcurrentModificationException();

 private class Itr implements Iterator<E> {
        int expectedModCount = modCount; // 迭代器生成的时候赋值

                public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

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

可以看得调用它们之前和之后都会做判断,通过了才整个返回集合

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

如果迭代器遍历

    @Test
    public void g1111() {
        ArrayList<String> al = new ArrayList<String>();
        al.add("1");
        al.add("2");
        al.add("3");
        al.add("4"); // 程序运行到这
        /*
         *  ArrayList.iterator
         *     public Iterator<E> iterator() {
                    return new Itr(); // 在这打断点,然后f5一步步进去
                }

                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; // 你会发现只有获得迭代器时同步一次
         */

        for (String string : al) {
            System.out.println(string);
        }

    }