[concurrency-interest] Attempt at yet another mostly-concurrent result cache

Joe Bowbeer joe.bowbeer at gmail.com
Tue Jan 9 07:47:59 EST 2007


I think a batch can always be lost between the time it is cached and
the time it is synchronized:

  Batch prev = cache.putIfAbsent(batchKey, batch);
  if (prev != null) batch = prev; // flip refs
  // LOST HERE
  synchronized (batch) { ... }

You can plug the hole by retesting inside a loop:

BatchResult process(Message msg) {
  String batchKey = msg.getBatchId();
  while (true) {
    Batch batch = cache.get(batchKey);
    if (batch == null) {
      batch = new Batch();
      Batch prev = cache.putIfAbsent(batchKey, batch);
      if (prev != null) batch = prev; // flip refs
    }
    // we have a batch that was cached at one time
    synchronize (batch) {
      if (batch != cache.get(batchKey))
        continue;
      batch.add(msg);
      if (!batch.isReady())
        return null;
      cache.remove(batchKey);
      return batch.toResult();
    }
  }
}

If you added a Lock to Batch then you might be able to improve
efficiency by locking the newly constructed Batch before adding it to
the cache.  Then you'd be sure no other thread could steal your new
batch before you got a chance to use it.

Note that adding a loop raises the possibility of starvation (live-lock).

(What's the best way to plug that hole?)

--Joe


More information about the Concurrency-interest mailing list