Implementing a simple cache with Java

In this post I’ll present a simple cache written in Java. It can be used to store objects of any kind or specific types only. The objects will expire after a certain time that can be customized too. Since this cache is really simple I didn’t implement a caching strategy nor an option for a maximum capacity.

You can download the Eclipse project as tar or zip or browse the code online here.

Basic operations

The cache supports these basic operations: you can put and get objects. If you put an object you can specify a time in seconds – after this time period the object will be remove from the cache.

Getting an object from the cache is simple too and you’ve also got the possibility to specify the type of the object you’re retrieving from the cache – this adds some type safety.

Have a look at this sample code:

SimpleCache<Integer> intCache = new SimpleCache<Integer>();
intCache.put("one", 1);
assertEquals(new Integer(1), intCache.get("one"));

This creates a SimpleCache that holds objects derived from Integer. Since you parameterized this cache with Integer you’ll only be able to put and get integers.

If you want to save all different kinds of objects in the cache that’s no problem at all. If you do this you can use the convenience method get which performs a cast for you. Have a look at this example:

SimpleCache cache = new SimpleCache();
cache.put("one", 1);
cache.put("str", "Some string");
assertEquals(new Integer(1), cache.get("one", Integer.class));
assertEquals("Some string", cache.get("str", String.class));

However, I think it’s better to create several instances of SimpleCache that stores objects of a specific type.

Removing expired objects

Once an object is expired we want to remove it from the cache. The SimpleCache class supports two ways of removing old objects:

  1. if the get method is called we’ll check whether the object that’s about to be returned is expired. If that’s the case we’ll remove it from the cache.
  2. a thread that runs periodically removes expired objects from the cache.

Both features reside in implementations of Runnable so they can be executed in separate threads. This way the basic operations will not be slowed down by this kind of housekeeping.

With Java 5 it’s easy to schedule recurring tasks with the Executors class. To remove expired objects from the cache we can use this code:

Runnable cleaner = new Runnable() {
  public void run() { /* remove expired objects here */ }
};
Executors.newScheduledThreadPool(1)
         .scheduleWithFixedDelay(cleaner, 0, 30, TimeUnit.SECONDS);

Conclusion

I presented a very simple cache written in Java that stores objects of any kind. It’s configurable, type safe and easy to use; it should be pretty easy to integrate this cache into an existing project.

I’ve tried to keep the cache fast: certain tasks will be executed in threads to speed things up. But don’t worry because the threads are easy to maintain and to understand.

13 comments ↓

  • Kevin says:
    Excellent post. This is exactly what I needed. It is really helping me re-learn a bunch of Java stuff that I should already know :-)
  • Vladislav says:
    Nice job, Christian!

    I just like to pay attention that if you put or remove an element to the cache during the expiration removal process (name : expire.keySet()) you will get ConcurrentModificationAccessException for sure.

    A simple solution could be to surround your code with dedicated synchronization lock.

    Cheerio,
    Vladislav

  • Hi Vladislav,
    although I haven’t experienced this exception yet, you’re right: we should add some type of locking here. Thank you for the hint!
  • sunil kumar says:
    Good stuff.
    good to start with basic caching mechanism
  • Bass says:
    Great intro to caching. But can you explain why you need a separate thread each time the get method is called? It appears to be an on-demand rather than a housekeeping activity so why would you need a another thread just for that?
  • Hi Bass,
    we don’t really need this extra thread because the get method makes sure that it doesn’t return old data. But in case the get method isn’t called and we keep adding objects to the cache over and over again, none of them will be removed which may result in an OutOfMemoryError – to prevent this I added this housekeeping thread.
  • Adriaan says:
    Hi Christian,

    The approach I used to implement a cache like yours was to use java.util.LinkedHashmap. This offers functionality to set a limit to the size of the cache and remove the least recently used item from the cache when the limit is exceeded. Advantages are that you don’t need a scheduled worker thread to clean up your cache and the maximum size of the cache can be pre-determined.

  • Hi Adriaan,
    thanks for the hint – it’s a great idea!
  • John says:
    hi Christian,

    How do you modify the code as Vladislav mentioned to prevent ConcurrentModificationAccessException from happening during the expiration removal process?

    Will this work (adding synchronized keyword to the run method)?

    public synchronized void run() {
    for (final String name : expire.keySet()) {


    }
    }

  • Hi John,
    I’m pretty sure that adding synchronized to the run method of the thread won’t cut it. Instead, you should sync on this to make sure that both objects named objects and expire can’t be modified during the expiration removal process.
  • John says:
    Hi Christian,

    Here’s what I understood from you. Below is what I think should work now. Correct me if I’m wrong.

    private Runnable createRemoveRunnable(final String name)
        {
            return new Runnable()
            {
                public void run()
                {
                    synchronized (this)
                    {
                        objects.remove(name);
                        expire.remove(name);
                    }
                }
            };
        }

     

  • Hi John,
    that’s exactly what I thought about.
  • vikas says:
    Hi Christian,

    Great and simple solution.

Leave a Comment