任何人都可以通过ConcurrentModificationException解释我吗? [英] Can anyone explain me over 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中究竟发生了什么
。我无法理解这是如何解决ConcurrentModificationException
问题。 - 案例2是否改变了实现
ArrayList
到CopyOnWriteArrayList
推荐?
- Can anyone explain me what is exactly happening in
case 1
. I am not able to understand how this solves theConcurrentModificationException
issue. - Is the case 2 changing the implementation from
ArrayList
toCopyOnWriteArrayList
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 ConcurrentModificationException
s 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屋!