This page introduces the
reference implementation of our example application.

As we will show in the JSR107 introduction in part 02,
Java Caches are based on
In order to introduce the example application, we present a
ConcurrentMap-based implementation here, and point out the shortcomings
from not using caches.

We will refer to this implementation in the following parts
when we point out the differences between a cache and a ConcurrentMap.

ConcurrentMap allows the implementation to be thread safe without using
synchronized blocks
. This is the main feature that makes ConcurrentMap
suitable as the basic type for distributed caches: While synchronization works
well in a single VM, it cannot be used across multiple VMs.
As we will see in part 03 and
part 04, ConcurrentMap’s atomic
operations can be implemented in a distributed way scaling across multiple VMs.

The ConcurrentMap-based implementation shown here is obviously incomplete:
As there is no housekeeping, the heap will grow with each user. This will
eventually result in an OutOfMemoryError.


The ServletContextListener
initializes the map and stores it in the Servlet context:

public void contextInitialized(ServletContextEvent servletContextEvent) {
    ServletContext context = servletContextEvent.getServletContext();
    context.setAttribute(CACHE, new ConcurrentHashMap<String, UserEventList>());

The RestInterface reads the map from the Servlet context:

private ServletContext context;
private ConcurrentMap<String, UserEventList> map;

public void init() {
    map = (ConcurrentMap) context.getAttribute(CACHE);


The contextDestroyed()
method is empty, as there is no need for shutting down the Map.

public void contextDestroyed(ServletContextEvent servletContextEvent) {}


The RestInterface provides the Web services for writing and searching

public void appendEvent(@PathParam("user") String user, String msg) {
    boolean success;
    map.putIfAbsent(user, UserEventList.emptyList());
    do {
        UserEventList oldMsgList = map.get(user);
        UserEventList newMsgList = UserEventList.append(oldMsgList, msg);
        success = map.replace(user, oldMsgList, newMsgList);
    while ( ! success );


public List<String> searchByUser(@PathParam("user") String user) {
    UserEventList result = map.get(user);
    if ( result == null ) {
        return new ArrayList<>();
    return result.getMessages();

How To Run

Our example code is hosted on GitHub.
The Map-based implementation can be run with maven:

mvn tomcat7:run-war -pl part01 -am verify

The Web interface is then accessible via


This is the last page of our introduction of the example application.
In the next part, we will show how the ConcurrentMap can be replaced
with a local cache: