我有一个类似于下面的方法:
public void addSubjectsToCategory() {
final List<Subject> subjectsList = new ArrayList<>(getSubjectList());
for (final Iterator<Subject> subjectIterator =
subjectsList.iterator(); subjectIterator.hasNext();) {
addToCategory(subjectIterator.next().getId());
}
}
Run Code Online (Sandbox Code Playgroud)
当它同时为同一个用户(另一个实例)运行时,有时它会抛出NoSuchElementException.根据我的理解,有时subjectIterator.next()在列表中没有元素时执行.仅在访问时会发生这种情况.方法同步会解决这个问题吗?
堆栈跟踪是:
java.util.NoSuchElementException: null
at java.util.ArrayList$Itr.next(Unknown Source)
at org.cmos.student.subject.category.CategoryManager.addSubjectsToCategory(CategoryManager.java:221)
Run Code Online (Sandbox Code Playgroud)
该堆栈跟踪失败addToCategory(subjectIterator.next().getId());.
迭代器的基本规则是在使用迭代器时不得修改底层集合.
如果你有一个单独的线程,这个代码似乎没有任何问题,只要getSubjectsList()不返回null addToCategory()或者getId()有一些奇怪的副作用会修改subjectsList.但请注意,您可以将for循环重写得更好(for(Subject subject: subjectsList) ...).
从您的代码判断,我最好的猜测是你有另一个线程正在修改subjectsList其他地方.如果是这种情况,使用SynchronizedList可能无法解决您的问题.据我所知,同步仅适用于列出的方法,如add(),remove()等,迭代过程中不锁定的集合.
在这种情况下,添加synchronized到该方法也无济于事,因为另一个线程在其他地方做了令人讨厌的事情.如果这些假设是正确的,那么最简单和最安全的方法是创建一个单独的同步对象(即Object lock = new Object())然后放置synchronized (lock) { ... }此for循环以及程序中修改集合的任何其他位置.这将阻止其他线程在此线程迭代时进行任何修改,反之亦然.
| 归档时间: |
|
| 查看次数: |
601 次 |
| 最近记录: |