任何人都可以通过ConcurrentModificationException解释我吗?

the*_*ava 3 java

案例1:这不会导致ConcurrentModificationException?任何人都可以告诉我为什么这不会导致ConcurrentModificationException.

public class UpdatePeople {
    List < People > records = new ArrayList < People > ();

    public class AsyncTask extends AsyncTask < Void, Void, Boolean > {
        List < People > people;

        public AsyncTask(List < People > allergy) {
            this.people = people;
        }@
        Override
        protected Boolean doInBackground(Void...params) {
            List < String > responses = new ArrayList < String > ();
            for (People peopleList: this.people) {

            }

        }

    }
}
Run Code Online (Sandbox Code Playgroud)

情况2:这导致ConcurrentModificationException我正在尝试访问AsyncThread中不是线程安全的人员列表.我可以让我的人员列表实现CopyOnWriteArrayList哪些是线程安全的,这应该工作.

public class UpdatePeople {
        List < People > records = new ArrayList < People > ();

        public class AsyncTask extends AsyncTask < Void, Void, Boolean > {
            @
            Override
            protected Boolean doInBackground(Void...params) {
                List < String > responses = new ArrayList < String > ();
                for (People peopleList: records) {

                }

            }

        }
    }
Run Code Online (Sandbox Code Playgroud)
  1. 任何人都可以解释我到底发生了什么case 1.我无法理解这是如何解决这个ConcurrentModificationException问题的.
  2. 案例2是否将实施ArrayList改为CopyOnWriteArrayList推荐?

添加例外:

05-28 20:34:21.073:E/XXX(904):未捕获的异常是:05-28 20:34:21.073:E/XXX(904):java.lang.RuntimeException:执行doInBackground()时发生错误05-28 20:34:21.073:E/XXX(904):在android.os.AsyncTask $ 3.done(AsyncTask.java:299)05-28 20:34:21.073:E/XXX(904):at java .util.concurrent.FutureTask $ Sync.innerSetException(FutureTask.java:273)05-28 20:34:21.073:E/XXX(904):at java.util.concurrent.FutureTask.setException(FutureTask.java:124) 05-28 20:34:21.073:E/XXX(904):at java.util.concurrent.FutureTask $ Sync.innerRun(FutureTask.java:307)05-28 20:34:21.073:E/XXX(904) :at java.util.concurrent.FutureTask.run(FutureTask.java:137)05-28 20:34:21.073:E/XXX(904):at android.os.AsyncTask $ SerialExecutor $ 1.run(AsyncTask.java: 230)05-28 20:34:21.073:E/XXX(904):at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)05-28 20:34:21.073:E/XXX(904) :at java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:569)05-28 20:34:21.073:E/XXX(904):at java.lang.Thread.run(Thread.java:856)05-28 20:34:21.073:E/XXX(904):引起:java.util.ConcurrentModificationException 05-28 20 :34:21.073:E/XXX(904):at java.util.ArrayList $ ArrayListIterator.next(ArrayList.java:569)

Dir*_*irk 7

一般来说ConcurrentModificationException,如果您尝试在迭代时修改集合,则会引发a.例如:

public class Main {

    public static void main(String[] args) 
    throws Exception {

        final List<Object> c1 = new ArrayList<Object>(Arrays.<Object>asList(1, 2, 3));
        for (Object o: c1) c1.remove(o);
    }
}
Run Code Online (Sandbox Code Playgroud)

java.util.ConcurrentModificationException因为我们在迭代它时修改列表(NB:这里只涉及一个单独的线程),所以会导致at运行时.这是由列表的迭代器检测到并导致异常.

如果所需的修改是删除刚从迭代器接收的元素,则可以通过直接使用迭代器来实现所需的结果(在单线程情况下!).将for(每个)循环替换为:

final Iterator<Object> iterator = c1.iterator();

while (iterator.hasNext()) {

    final Object o = iterator.next();
    if (satisfiesSomeCriterion(o)) iterator.remove();
}
Run Code Online (Sandbox Code Playgroud)

但是,这对所有修改都不起作用.例如,添加不起作用.以下代码仍然失败:

for (Object o: c1) c1.add(Integer.valueOf(((Integer)o).intValue() + 10));
Run Code Online (Sandbox Code Playgroud)

如果底层集合是a List,您可以通过使用ListIterator而不是普通迭代器来解决此限制:

final ListIterator<Integer> iterator = c1.listIterator();

while (iterator.hasNext()) {

    final Integer o = iterator.next();
    if (satisfiesSomeCriterion(o)) iterator.add(Integer.valueOf(o.intValue() + 10);
}
Run Code Online (Sandbox Code Playgroud)

但请注意,这不等于上面给出的代码(插入元素的其他位置).另请注意,这ListIterator.add是一种可选方法; 一个实现可能会UnsupportedOperationException在调用它时抛出一个.

上述所有内容仅适用于单线程机箱.如果您尝试在没有正确同步的情况下同时从多个线程访问同一个集合,则会出现一组全新的问题,因为这不仅可能导致ConcurrentModificationException迭代线程中的s,还会破坏集合内部数据的完整性结构.

你可以做一些事情:

  • 使用并发感知集合(例如CopyOnWriteArrayList您已经提到过的)
  • 通过Collections.synchronizedList(...Set,...Whatever)包装集合.但请注意,在这种情况下,您仍然需要为迭代提供适当的锁定规则.有关详情,请参阅此答案.
  • 在将原始集合传递给后台作业之前制作副本(并确保后台作业是使用该副本的唯一线程)
  • 通过synchronized块保护集合的所有使用(例如,使用集合本身作为"监视器"对象,尽管更好:使用专用的监视器对象).