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:
- 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. - 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.
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 🙂
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!
Good stuff.
good to start with basic caching mechanism
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.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!
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 namedobjects
andexpire
can’t be modified during the expiration removal process.Hi Christian,
Here’s what I understood from you. Below is what I think should work now. Correct me if I’m wrong.
Hi John,
that’s exactly what I thought about.
Hi Christian,
Great and simple solution.
The piece of stuff u provided is good but u should have provided the full code so that we can understand whole program
Hi swaroop,
you can download the Eclipse project as tar or zip or browse the code online here.
Thanks for your solution, helped a lot!
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.
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:
Both solutions may help you limiting the set you will have to work on during an expiry run.
Is it required to have a separate thread to remove entries from cache ? Like below
Can’t we keep the same inside after
threads.execute(createRemoveRunnable(name));
inremoveExpired()
method ?Hi Maldalapu,
sure you can do this. Remember encapsulating these two operations in a
synchronized
block, like it was mentioned earlier in the comments.Here is what I have done:
And is it required to keep synchronized block in
removeExpired()
method ? If yes please let me know how do I do that ?Hi Maldalapu,
sure, that’s one way to do it. You only need one synchronized block and won’t have to add
synchronized
to every method.Thanks a Lot Christian,
I got what I needed.
It is described in very simple and precise manner. I like it. It would help me out in my exisiting project.
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 !
Dear Indrajit,
I’m glad this post helped you. Don’t forget to checkout the source code and play with it a bit – this way you’ll probably understand the concepts even better.
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
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.
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..?
Hi F1,
please ask the authors of
purple.jar
how to do this since I’ve never heard of this software before and don’t know how it works.please tell me we need to add any extra headers for the cache
As some one pointed out earlier, it is easier to use LinkedHashMap if you want to implement a simple LRU cache. For heavily multi threaded applications, I would recommend ConcurrentHashMap instead of Synchronized Hashmap. Here is very good article on concurrent hash maps http://www.ibm.com/developerworks/java/library/j-jtp08223/index.html
Hi Anupam,
thank you for the hint and the link to the great article – much appreciated.
can i get the complete code for implementing caching in proxy server using java.
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.
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…
Hi Colin,
simply create a getter for the property
objects
and implement acompare
method that allows you to hand over theobjects
from the otherSimpleCache
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.