HRJ HRJ - 1 year ago 108
Java Question

When is the ConcurrentModificationException thrown in GAE?

I am reading the official GAE documentation on transactions and I can't understand when a

is thrown.

Look at one of the examples which I am copy-pasting here:

int retries = 3;
while (true) {
Transaction txn = datastore.beginTransaction();
try {
Key boardKey = KeyFactory.createKey("MessageBoard", boardName);
Entity messageBoard = datastore.get(boardKey);

long count = (Long) messageBoard.getProperty("count");
messageBoard.setProperty("count", count);

} catch (ConcurrentModificationException e) {
if (retries == 0) {
throw e;
// Allow retry to occur
} finally {
if (txn.isActive()) {

Now, all the writes to the datastore (in this example) are wrapped under a transaction. So why would a
be thrown?

Does it happen when some other code which is not wrapped in a transaction updates the same entity that is being modified by the above code? If I ensure that all code that updates an Entity is always wrapped in a transaction, is it guaranteed that I won't get a

Answer Source

I found the answer on the GAE mailing list.

I had a misconceived notion of how transactions work in GAE. I had imagined that beginning a transaction will lock out any concurrent updates to the datastore until the transaction commits. That would have been a performance nightmare as all updates would block on this transaction and I am happy that this isn't the case.

Instead, what happens is, the first update wins, and if a collision is detected in subsequent updates, then an exception is thrown.

This surprised me at first, because it means many transactions will need a retry logic. But it seems similar to the PostgreSQL semantics for "serializable isolation" level, though in PostgreSQL you also have the option to lock individual rows and columns.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download