ConcurrentHashMap computeIfAbsent method in Java 8

The very nifty method computeIfAbsent has been added in the ConcurrentMap interface in Java 8 as part of the atomic operations of the ConcurrentMap interface. It’s more precisely a default method that provides an alternative to what we use to code ourselves:

if (map.get(key) == null) {
   V newValue = mappingFunction.apply(key);
   if (newValue != null)
      return map.putIfAbsent(key, newValue);
   }
}

but this time providing a function as a second argument.

Most often this method will be used in the context of ConcurrentHashMap in which case the method is implemented in a thread-safe synchronised way.

In terms of usage the method is handy for situations where we want to maintain a thread-safe cache of expensive one-off computed resources.

Here’s another example of holding a key-value pair where value is a thread-safe counter represented by an AtomicInteger:

private final Map counters = new ConcurrentHashMap();

private void accumulate(String name) {
    counters.computeIfAbsent(name, k -> new AtomicInteger()).incrementAndGet();
}
Advertisements

Future and FutureTask

Futures and FutureTasks are a great way to represent the result of an operation that is running on a thread. It also provides facilities like future.get() that is blocking while the Future operation is not yet complete.

Submitting a Callable (that defers from Runnable in that it returns a value and can throw exceptions as opposed to Runnable) forces the Executor to return back a Future. This is very useful technique for all those cases where we have expensive operations and the sooner we start them the better. On the other end when we invoke future.get() this operation blocks until we get a result back from the operation. For most of our purposes it is safe to assume the result of our operation to be represented by a Future that when it completes it is notifying us.

We can create a Future:

final Future future = Executors.newCachedThreadPool().submit(ourCallable);

or alternatively a FutureTask:

FutureTask<Callable> future = new FutureTask(ourCallable);
Thread thread = new Thread(futureTask);
thead.start();

On the other end we can expect the result of our expensive operation as follows:

Object result = future.get();

Executors

Have you ever done the following:

new Thread(runnable).start();

all over the place, all over the code? What if there was a centralised pool for all sorts of threads to live in? This way we could achieve a certain level of thread reuse and do other smart stuff like pre-initialisation etc.

Enter Executors. As part of the java.util.concurrent package comes this amazing utility class with static factory methods as convenience methods to offer different flavours of ThreadPoolExecutor.

FixedThreadPool

We can create a FixedThreadPool as follows:

final Executor executor = Executors.newFixedThreadPool(5);

behind the scenes the static factory method is

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

This basically creates a thread pool of core size 5 and max pool size of 5. Also the pooled threads are not released (0 minutes as the third and fourth argument) and are maintained, even in idle state, for all the lifetime of the FixedThreadPool Executor. Lastly, a LinkedBlockingQueue of Runnables is provided to keep hold of the tasks and submit to worker threads.

If we now execute some runnable like this:

executor.execute(new Runnable(){public void run(){/*do work here*/}});

say for instance passing 10 runnables then 5 of them will be submitted as pooled threads and all the remaining ones would be cached in the queue. From that point onwards the 5 queued runnables will be passed one by one to the running 5 pool threads. Interestingly, if there are no more runnables for the 5 created threads, then these threads remain in idle state inside of the FixedThreadPool patiently waiting for new runnables until the fixed thread pool executor is shut down.

If we wish not to lose time we can initialise the thread pool and create our core max pool of threads before the first runnables to be submitted:

int count = ((ThreadPoolExecutor) executor).prestartAllCoreThreads();

SingleThreadExecutor

We can create a SingleThreadExecutor instance by calling the static factory method:

final Executor executor = Executors.newSingleThreadExecutor();

which behind the scenes calls the ThreadPoolExecutor constructor in the following flavour:

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue()));
    }

Based on these arguments core pool size = max pool size = 1 and this thread is kept even as idle in the pool until the end of the single thread executor. Similarly as the FixedThreadPoolExecutor there is a LinkedBlockingQueue of Runnables to hold on the tasks before submitting them one by one on to the sole running thread.

CachedThreadPool

A CachedThreadPool Executor can be created as follows:

final Executor executor = Executors.newCachedThreadPool();

which makes a call to the ThreadPoolExecutor constructor with the following arguments:

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

So although the static factory method has no arguments the ThreadPoolExecutor constructor which is called underneath creates an unbounded ThreadPoolExecutor where all runnables are making it into the executor and after successful completion they stay in idle state in the thread pool for 60 seconds before they get decommissioned if not getting used earlier.