Java:为什么ConcurrentModificationException与同步列表一起出现?

问题描述 投票:1回答:3

使用此代码:

public class SynchroApp {

    public static void main(String[] args) {

        final List<String> unsyList = new ArrayList<>();
        final List<String> syList = Collections.synchronizedList(unsyList);

        TimerTask changeList = new TimerTask() {
            boolean addElem = false;

            @Override
            public void run() {
                // add / remove elements to keep size between 2 and 9
                if (syList.size() < 2)
                    addElem = true;
                else if (syList.size() > 8)
                    addElem = false;
                if (addElem)
                    syList.add(String.valueOf(System.currentTimeMillis()));
                else
                    syList.remove(0);
            }
        };

        TimerTask reverseList = new TimerTask() {
            @Override
            public void run() {
                try {
                    for (String s : syList)
                        s = new StringBuffer(s).reverse().toString();
                } catch (Exception e) {
                    System.out.println("Exception: " + e);
                }
            }
        };

        new Timer().scheduleAtFixedRate(changeList, 0L, 30L);
        new Timer().scheduleAtFixedRate(reverseList, 0L, 20L);
    }
}

为什么我还会在ConcurrentModificationException上收到一些Iterator.next

编辑:reverseList中列表元素的更新无效(如评论中所述)。此代码应按预期工作:

for (int i = 0; i < syList.size(); i++)
    syList.set(i, new StringBuffer(syList.get(i)).reverse().toString());
java arraylist iterator concurrentmodification
3个回答
1
投票

即使是大多数同步集合也不喜欢修改和迭代。从Collections.synchronizedList的API描述:

当迭代它时,用户必须手动同步返回的列表:

List list = Collections.synchronizedList(new ArrayList()); ... synchronized (list) { Iterator i = list.iterator(); // Must be in synchronized block while (i.hasNext()) foo(i.next()); }

另外:您可以使用java.concurrent中的集合。它们通常具有更精细的同步方法。


3
投票

因为您在迭代时修改列表。

请注意,同步列表仅使其每个方法及其迭代器的方法同步。迭代同步列表仍然是非原子操作,涉及对同步方法的多次调用。如果你想让整个迭代成为原子,你必须明确地同步它,使用列表本身作为锁:

synchronized (syList) {
    for (String s : syList) {
        s = new StringBuffer(s).reverse().toString();
    }
}

0
投票

迭代器和修饰符都必须使用synchronizedList()才能在对象上进行正确的锁定/同步。

© www.soinside.com 2019 - 2024. All rights reserved.