Friday, September 25, 2009

Keeping a current timestamp in a Java concurrent map

Tricker than I like: In Java, how do you keep a map with the values being the "most recent timestamp" for the key? How do you do this for a concurrent map with multiple threads updating?

boolean isLatest(final K key, final long newTimestamp,
        final ConcurrentMap<K, Long> map) {
    Long oldTimestamp = map.putIfAbsent(key, newTimestamp);

    // If we are first, there is no previous to compare
    // with
    if (null == oldTimestamp)
        return true;

    // Make sure we are still the most recent
    while (newTimestamp > oldTimestamp) {
        if (map.replace(key, oldTimestamp, newTimestamp))
            // No other thread has updated, we are most
            // recent
            return true;

        // Another thread got here first, recheck
        oldTimestamp = map.get(key);
    }

    // Another thread put in a newer update, we are not
    // most recent
    return false;
}

As with all multi-threaded coding, bugs are easy to make and hard to spot. If I have made one, please let me know!

UPDATE: Fixed a typo. Thanks, David!

4 comments:

CARFIELD said...

I would more interested about the actual usecase behind, would you share more about why do you need to do that?

Brian Oxley said...

Carfield, I have a series of threads processing work items. The same item can get processed more than once and by more than one thread. There is a unique id for each item, and there is also a timestamp on each item indicating when it was last processed.

The currrent timestamp map ensures that I can keep track of when the most recent processing of a work item took place.

I happen to need this particular detail as a business requirement for some more complex processing.

David said...

What is this delegate.get(key)? Or should it be map.get(key)?

CARFIELD said...

I just wonder, how about put the items ( key ) into the stack? Then just top() will get the most recent processing of a work item.

Just wondering