JRect 2018-05-07 08:30 采纳率: 0%
浏览 1240
已结题

多线程处理一个任务,报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;
}

}


  • 写回答

4条回答 默认 最新

  • 计算机123456 2018-05-07 13:58
    关注

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

    评论

报告相同问题?

悬赏问题

  • ¥15 关于github的项目怎么在pycharm上面运行
  • ¥15 内存地址视频流转RTMP
  • ¥100 有偿,谁有移远的EC200S固件和最新的Qflsh工具。
  • ¥15 找一个QT页面+目标识别(行人检测)的开源项目
  • ¥15 有没有整苹果智能分拣线上图像数据
  • ¥20 有没有人会这个东西的
  • ¥15 cfx考虑调整“enforce system memory limit”参数的设置
  • ¥30 航迹分离,航迹增强,误差分析
  • ¥15 Chrome Manifest扩展引用Ajax-hook库拦截请求失败
  • ¥15 用Ros中的Topic通讯方式控制小乌龟的速度,走矩形;编写订阅器代码