Home > Java > Creating a simple cache in Java using a LinkedHashMap and an Anonymous Inner Class

Creating a simple cache in Java using a LinkedHashMap and an Anonymous Inner Class

June 28th, 2009
The processing costs for selecting a value from a database-table are fairly high compared to the costs having the value already in memory. So it seems preferrable to use some smart caching-mechanism that keeps often used values in your application instead of retrieving these values from resources somewhere ‘outside’.

Most frameworks have at least one cache implementation onboard, but there also exist several other implementations of caches like e.g. EHCache. Even ordinary HashMaps/Hashtables can serve as caches also.

A critial factor when using caches in Java is the size of the cache: when your cache grows too big, the Java Garbage Collector has to cleanup more often (which consumes time) or your application even crashes with a java.lang.OutOfMemoryError.

One way to control the memory-consumption of caches is to use SoftReferences in HashMaps/Hashtables, another one is to throw away old or unused content by implementing a caching-strategy like e.g. LRU.

A simple LRU-cache already ships within the components of the Java Standard Library: the LinkedHashMap. All you have to do is to tell your application whether the eldest entry in the map should be retained or removed after a new entry is inserted. Additionally a special constructor has to be used that defines the orderingMode for the map: ‘true’ for access-order (LRU), ‘false’ for insertion-order.

Suppose we want to cache a mapping of String-Names to Integer-Ids with a maximum size of 100 entries.
How that can be done is shown by the example below with the use of an Anonymous Inner Class that overrides the removeEldestEntry-method of the LinkedHashMap.
 Java |  copy code |? 
01
package com.java_blog;
02
 
03
import java.util.LinkedHashMap;
04
import java.util.Map;
05
 
06
 public class LinkedHashMapExample { 
07
 
08
      private final static int CACHE_MAX_SIZE = 100; 
09
      private LinkedHashMap<String, Integer> cache;
10
 
11
     @SuppressWarnings("serial")
12
      public LinkedHashMapExample() { 
13
 
14
            this.cache = new LinkedHashMap<String, Integer>(CACHE_MAX_SIZE, 0.75f, true) { 
15
                  protected boolean removeEldestEntry(
16
                             Map.Entry<String, Integer> eldest) {
17
                        // Remove the eldest entry if the size of the cache exceeds the
18
                        // maximum size
19
                        return size() > CACHE_MAX_SIZE;
20
                  }
21
            };
22
      } 
23
 
24
      public Integer getIdForName(String name) {
25
             Integer id = cache.get(name);
26
 
27
             if (id != null)
28
                  return id;
29
 
30
            else {
31
                  id = getIdForNameFromExternal(name);
32
                   // TODO Tino, 24.06.2009: what to do if no id could be found for the
33
                  // provided name in external resource?
34
                  cache.put(name, id);
35
                  return id;
36
            }
37
      }
38
 
39
      private Integer getIdForNameFromExternal(String name) {
40
             // TODO Tino, 24.06.2009: replace dummy-code
41
            return 1;
42
      }
43
}

Happy Coding,

Tino


Share/Save/Bookmark

tino Java ,

  1. June 29th, 2009 at 01:48 | #1
    I don’t think that’s an LRU cache. That’s a Least Recently Added cache. For it to be LRU, on a cache-hit, the item should be moved to the beginning of the list.
  2. June 29th, 2009 at 08:37 | #2
    Hi Robin,

    you’re absolutely correct! I forgot to invoke the special constructor for the LinkedHashMap to use access-ordering. I’ve corrected that part.

    Thanks!
  3. Joe
    July 22nd, 2009 at 19:48 | #3
    Check for synchronization issues.

    From Sun’s LinkedHashMap API doc:

    ”Note that this implementation is not synchronized.”
  1. No trackbacks yet.
Security Code: