[concurrency-interest] Questions on ConcurrentHashMap

Jed Wesley-Smith jed at atlassian.com
Fri Nov 30 03:10:17 EST 2007


I have a utility class for that encapsulates lockless lazy loading 
stuff. It locks only when multiple threads call get while run is 
occuring (FutureTask implementation).

/**
 * Thread-safe lock-less reference that is not constructed until required.
 * <p>
 * Implement create() in implementation.
 */
public abstract class LazyLoadedReference<V>
{
    private final AtomicReference<FutureTask<V>> ref = new 
AtomicReference<FutureTask<V>>();

    public final V get()
    {
        FutureTask<V> future = ref.get();
        if (future == null)
        {
            // create a Future
            future = new FutureTask<V>(new Callable<V>()
            {
                public V call() throws Exception
                {
                    return create();
                }
            });
            // set the reference only if it is still null
            ref.compareAndSet(null, future);
            // get the future that ref now holds (may be different to above
            future = ref.get();
        }
        while (true)
        {
            try
            {
                future.run();
                return future.get();
            }
            catch (InterruptedException interruptAndTryAgain)
            {
                Thread.currentThread().interrupt();
            }
            catch (ExecutionException e)
            {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * The object factory method, guaranteed to be called once and only 
once.
     */
    protected abstract V create();
}

Then you simply need to implement create() in your implementation. 

Gregg Wonderly wrote:
> Grace Kwok wrote:
>   
>> I am trying to think of the most concurrent and correct way of
>> implementing this.
>>     
>
> When I have all or nothing situations like this, I will often rebuild the map 
> into a local referenced instance, and then overwrite the global reference with 
> the new instance to create an "atomic" swap to the new values without having to 
> "wait" for them everywhere else.
>
> Based on what I think you are doing on clear, it might look something like the 
> following.
>
> volatile ConcurrentHashMap<T,K> map = ...
>
> public void clear() {
> 	ConcurrentHashMap<T,K> newmap = ...
> 	fillmap( newmap );
> 	map = newmap;
> }
>
> But I am not clear on exactly when you fill the map.  If you fill the map on a 
> "get", then you may instead choose to use a future to cause those doing a get to 
> wait for the map to "appear" in a filled state.
>
> public void clear() {
> 	map = null;
> }
>
> volatile Future<ConcurrentHashMap<T,K>> mapFuture;
>
> public T get( K key ) {
> 	if( map == null ) {
> 		if( mapFuture == null ) {
> 			synchronized( mapLock ) {
> 				if( mapFuture == null )
> 					mapFuture = startMapBuild();
> 			}
> 		}
> 		map = mapFuture.get();
> 	}
> 	return map.get( key );
> }
>
> This focuses the locking into the moment that is needed while allow the 
> concurrency in ConcurrentHashMap to be exploited on gets().
>   

-------------- next part --------------
An HTML attachment was scrubbed...
URL: /pipermail/attachments/20071130/8519a113/attachment.html 


More information about the Concurrency-interest mailing list