Set上的Android ConcurrentModificationException

时间:2016-11-18 12:06:20

标签: java android concurrency

我已经阅读了很多有关此问题的SO问题,但我无法理解为什么我有java.util.ConcurrentModificationException

在课堂上我有这个:

private Set<RequestOrders> mRequests = new HashSet<>();
private final Object lock = new Object();

mRequest对象上的所有操作都被这样的同步语句包围:

public void handleOrder(RequestOrders order) {
    synchronized (lock) {
        if (!mRequests.contains(order)) {
            final sOrder = saveOrderOnDB(order);
            mRequests.add(sOrder);

            handleOrder(sOrder;
        }
    }
}

我收到了错误:

void notifyOrder(int type) {
    if (!mPause) {
        synchronized (lock) {
            for (RequestOrders request : mRequests) { // Error here while iterating
                if (.....) {
                    redirectOrders(request);
                } else if (....) {
                    ......
                    startService(.....);
                }
            }
        }
    } else {
        .....
    }
}

知道为什么吗?同步语句是否应该防止并发问题?

1 个答案:

答案 0 :(得分:1)

在您仍然在迭代mRequest集时,可能正在发生从Set中添加/删除RequestOrders的方法调用。因此,当您仍在迭代时,mRequest集的大小正在发生变化,从而导致错误。为了克服这个问题,你可以:

1 - 创建一个临时集,其中包含要添加到mRequest的所有对象。完成对mRequest集中所有对象的循环后,将临时集中的所有对象添加到mRequest集。

2-使用并发HashMap。

以下是如何使用第一种方法的示例:

private Set<RequestOrders> mRequests = new HashSet<>();
private Set<RequestOrders> backlog = new HashSet<>();

public void handleOrder(RequestOrders order) {
    synchronized (lock) {
        if (!mRequests.contains(order)) {
            final sOrder = saveOrderOnDB(order);
            backlog.add(sOrder);
            handleOrder(sOrder);
        }
    }
}

void notifyOrder(int type) {
    if (!mPause) {
        for (RequestOrders request : mRequests) { // Error here while iterating
            if (.....) {
                redirectOrders(request);
            } else if (....) {
                ......
                startService(.....);
            }
        }
        mRequests.addAll(backlog);
        backlog.clear();
    } else {
        .....
    }
}