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.

36 thoughts on “Implementing a simple cache with Java”

  1. 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 🙂

  2. 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

  3. 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?

  4. 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.

  5. 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.

  6. 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()) {


    }
    }

  7. 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.

  8. 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);
                    }
                }
            };
        }

     

  9. The piece of stuff u provided is good but u should have provided the full code so that we can understand whole program

  10. Hi Christian,
    Good stuff, I was doing almost the same thing by wrapping the Object in an inner class with an extra data member “time stamp” attached and scavanging in backgroung via a thread.
    But my design as well yours has a performance issue if the cache is storing Millions of records (that happens in case of Financial Soultions when market moves every time in sp. Equities and FX ) in a minute ( i.e. expiry time is 2 minutes)
    Because we have to iterate through keyset of millions of records.
    I am looking for a much effecient solution, any comments are welcomed.

  11. Hi Rohit,
    as the name implies SimpleCache is a really simple solution to cache objects of a certain type. It isn’t very sophisticated but may serve as a foundation for a more intelligent implementation.
    In your case with lots and lots of records I could think of the following solutions:

    1. limit the amount of cached objects and throw away the oldest objects on expiry not making any use of expiry after a certain amount of time.
    2. split the cache into various smaller segments that can be handled in a reasonable amount of time. Right now the implementation has got a map of objects and you could extend that to a map containing maps of objects. During the expiry run only work on a subset of these maps in the larger map.

    Both solutions may help you limiting the set you will have to work on during an expiry run.

  12. Is it required to have a separate thread to remove entries from cache ? Like below

    public void run() {
      cacheStore.remove(name);
      expire.remove(name);
    }

    Can’t we keep the same inside after threads.execute(createRemoveRunnable(name)); in removeExpired() method ?

  13. Here is what I have done:

    private void createRemoveRunnable(final K name) {
      synchronized (this) {
        cacheStore.remove(name);
        expire.remove(name);
      }
    }

    And is it required to keep synchronized block in removeExpired() method ? If yes please let me know how do I do that ?

  14. Hi All,

    I am new for caching concept but after reading simple caching in java, and all your’s comments i am happy it is giving more information to understand this concept and proceed further.

    Thanks !

  15. Hi Christian,
    Thanks so much about your code, I have noticed in comments we sill need to but synchronize block around maps when tries to remove. Can you please explain to me why I need that point as I can see you already creating synchronized map. or what if you used hashtable instead. Thanks

  16. Hi Kamel,
    if you’re using a synchronized map you don’t have to encapsulate it inside a synchronized block; the same holds true for a synchronized HashTable, which is just a certain implementation of a map.
    If you checkout the code in the comment above in more detail you’ll notice that two objects are altered inside the synchronized block. That said, the synchronized block makes sure that changing both objects is a single atomic operation.

  17. i m using purple.jar and i have written a logic to create cacheKey and store the list of data, when the user sign off’s i want to remove the cache and make it blank.
    how i ca achieve this..?

  18. Dear dolly,
    you can download the code for this simple caching implementation using the link above. The emphasis here really is simple: if you need anything sophisticated you will have to either extend my implementation or come up with your own.

  19. Hey, is there an easy way to remove an element from the cache? i am attempting to compare the contents of two caches, and if they are the same, erase one…

  20. Hi Colin,
    simply create a getter for the property objects and implement a compare method that allows you to hand over the objects from the other SimpleCache instance. This way you can iterate over the objects and if you find two identical objects you could remove the one from the local objects map. That should be it.

Comments are closed.