任何人都可以通过ConcurrentModificationException解释我吗? [英] Can anyone explain me over ConcurrentModificationException?

查看:129
本文介绍了任何人都可以通过ConcurrentModificationException解释我吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Case 1: This does not cause ConcurrentModificationException?. Can anyone tell me why does this not cause 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) {

            }

        }

    }
}

案例2:这会导致 ConcurrentModificationException ,因为我试图访问我的AsyncThread中的人员列表不是线程安全的。我可以让我的人员列表实现 CopyOnWriteArrayList 这是线程安全的,这应该可行。

Case 2: This causes ConcurrentModificationException as i am trying to access the List of people in my AsyncThread which is not thread safe. I can make my List of People implement CopyOnWriteArrayList which is thread safe and this should work.

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) {

                }

            }

        }
    }




  1. 任何人都可以解释一下案例1中究竟发生了什么。我无法理解这是如何解决 ConcurrentModificationException 问题。

  2. 案例2是否改变了实现 ArrayList CopyOnWriteArrayList 推荐?

  1. Can anyone explain me what is exactly happening in case 1. I am not able to understand how this solves the ConcurrentModificationException issue.
  2. Is the case 2 changing the implementation from ArrayList to CopyOnWriteArrayList recommended?

添加例外:


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):at
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)

05-28 20:34:21.073: E/XXX(904): Uncaught exception is: 05-28 20:34:21.073: E/XXX(904): java.lang.RuntimeException: An error occured while executing doInBackground() 05-28 20:34:21.073: E/XXX(904): at 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): Caused by: java.util.ConcurrentModificationException 05-28 20:34:21.073: E/XXX(904): at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:569)


推荐答案

一般来说,一个<如果您尝试在迭代时修改集合,则会引发code> ConcurrentModificationException 。例如:

Generally speaking, a ConcurrentModificationException is raised, if you try to modify a collection while iterating over it. For example:

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

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

will cause a java.util.ConcurrentModificationException at run-time, since we are modifying the list while iterating over it (NB: only a single thread involved here). This is detected by the list's iterator and causes the exception.

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

If the desired modification is the deletion of the very element just received from the iterator, you can achieve the desired result (in the single threaded case!) by working with the iterator directly. Replace the for(each) loop with:

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

while (iterator.hasNext()) {

    final Object o = iterator.next();
    if (satisfiesSomeCriterion(o)) iterator.remove();
}

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

This does, however, not work for all modifications. Additions, for example, won't work. The following code does still fail:

for (Object o: c1) c1.add(Integer.valueOf(((Integer)o).intValue() + 10));

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

If the underlying collection is a List, you may be able to work around this restriction by using a ListIterator instead of a plain iterator:

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

while (iterator.hasNext()) {

    final Integer o = iterator.next();
    if (satisfiesSomeCriterion(o)) iterator.add(Integer.valueOf(o.intValue() + 10);
}

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

but note, that this is not equivalent to the code given above (other placement of the element being inserted). Also note, that ListIterator.add is an optional method; an implementation might throw an UnsupportedOperationException when it is being called.

上面提到的所有内容都只适用于单线程的情况。如果你试图在没有正确同步的情况下同时从多个线程访问同一个集合,会出现一系列全新的问题,因为这不仅有可能导致 ConcurrentModificationException 在迭代线程中,但也破坏了集合内部数据结构的完整性。

All the things said above are applicable for the single-threaded case only. A whole new set of problems arises, if you try to access the same collection from multiple threads concurrently without proper synchronization, as this has not only the potential to cause ConcurrentModificationExceptions in the iterating thread, but also to destroy the integrity of the collection's internal data structures.

有几个你可以做的事情:

There are a few things you can do:


  • 使用并发感知集合(例如 CopyOnWriteArrayL ist 你已经提到了)

  • 通过 Collections.synchronizedList >包裹集合...设置 ...无论)。但请注意,在这种情况下,您仍然需要为迭代提供适当的锁定规则。有关详细信息,请参见此答案

  • 在将原始集合传递给后台作业之前制作原始集合的副本(并确保后台作业是使用该副本的唯一线程)

  • 通过 synchronized 块保护集合的所有用途(例如,使用集合本身作为monitor对象,尽管更好:使用专用的监视器对象)。

  • Use a concurrency-aware collections (such as the CopyOnWriteArrayList you already mentioned)
  • Wrap the collection via Collections.synchronizedList (...Set, ...Whatever). Note, though, that in this case you are still responsible for providing a proper locking discipline with respect to iteration. See this answer for details.
  • Make a copy of the original collection before passing it to the background job (and make sure, that the background job is the only thread using that copy)
  • Protect all uses of the collection by synchronized blocks (for example, using the collection itself as the "monitor" object, though better: using a dedicated monitor object).

这篇关于任何人都可以通过ConcurrentModificationException解释我吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆