The Map-based reference implementation
of our example application does not implement any housekeeping, which
will eventually lead to OutOfMemory errors as the

This part shows how to replace the ConcurrentMap with a Cache and utilize the
Cache’s eviction to limit the amount of memory used.

The following describes the Hazelcast example.


In Hazelcast, the role of the CacheManager
is taken by a

public void contextInitialized(ServletContextEvent servletContextEvent) {
    Config cfg = new Config();
    HazelcastInstance instance = Hazelcast.newHazelcastInstance(cfg);
    ConcurrentMap<String, UserEventList> map = instance.getMap("events");
    ServletContext context = servletContextEvent.getServletContext();
    context.setAttribute(CACHE, map);

Note that Hazelcast’s Cache directly implements ConcurrentMap, which means
that reading and writing data can be done with the the same
code as in the Map-based implementation.

By default, Hazelcast loads its config from a file named hazelcast.xml
in the Classpath. The following shows a simple configuration limiting
the Cache size to 1000 entries:

<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-2.1.xsd"
    <map name="events">
        <max-size policy="cluster_wide_map_size">1000</max-size>

As in the Map-based implementation, the
REST interface gets the ConcurrentMap from the

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

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


When the Hazelcast
Cache Manager is used for the first time, a Hazelcast member
will start automatically. On shutdown, the Hazelcast member must be terminated:

public void contextDestroyed(ServletContextEvent servletContextEvent) {


As the Hazelcast cache implements ConcurrentMap, the write code is
one-to-one the same as in the
Map-based reference implementation:

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 );


Like the write method, read is also a one-to-one copy of the
Map-based implementation:

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 example can be run with maven:

mvn tomcat7:run-war -pl part02.hazelcast -am verify

The Web interface is then accessible via

Note on Performance

As the local-only deployment involves no network interaction, the
performance is mainly influenced by the speed of serialization.

Unlike Ehcache, Hazelcast always performs serialization, which makes
Hazelcast not a good choice for single node caching.


This page showed how the ConcurrentMap in our example can be replaced with
a local Hazelcast instance. The last page of part 02 will show how the same
can be done with Infinispan:

Monitoring-Workshop 2017 12./13.9. Düsseldorf