
Cache simply means loading the data by some key and it should be in memory. If we are running our application in clustered mode then available implémentation is Coherence which can isolated interaction with DB and provided fail over and syncronization between multiple application cache.
Here is example how we can build LRU cache in java using concurrent package. This implementation will be fragile and blocking if we would have implemented cache using old synchronize idiom. Cache data is backed up by ConcurrentHashMap so that reading from cache is not blocked and writing to cache will have concurrent effect, it means only the buckets will be locked during write operation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ConcurrentLRUCache<Key, Value> { | |
private final int maxSize; | |
private ConcurrentHashMap<Key, Value> map; | |
private ConcurrentLinkedQueue<Key> queue; | |
public ConcurrentLRUCache(final int maxSize) { | |
this.maxSize = maxSize; | |
map = new ConcurrentHashMap<Key, Value>(maxSize); | |
queue = new ConcurrentLinkedQueue<Key>(); | |
} | |
/** | |
* @param key - may not be null! | |
* @param value - may not be null! | |
*/ | |
public void put(final Key key, final Value value) { | |
if (map.containsKey(key)) { | |
queue.remove(key); // remove the key from the FIFO queue | |
} | |
while (queue.size() >= maxSize) { | |
Key oldestKey = queue.poll(); | |
if (null != oldestKey) { | |
map.remove(oldestKey); | |
} | |
} | |
queue.add(key); | |
map.put(key, value); | |
} | |
/** | |
* @param key - may not be null! | |
* @return the value associated to the given key or null | |
*/ | |
public Value get(final Key key) { | |
return map.get(key); | |
} | |
} |
Caching Implementation without concurrency using wait() and notify()
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.learning.basic; | |
public class CacheImplementation { | |
Object lock = new Object(); | |
String[] arr = new String[5]; | |
public volatile static boolean isSet = false; | |
public void put(String data) throws InterruptedException { | |
while (true) { | |
synchronized (this) { | |
if (!isSet) { | |
System.out.println(" put it and make it true"); | |
isSet = true; | |
notify(); | |
} else { | |
wait(); | |
} | |
} | |
} | |
} | |
public void get() throws InterruptedException { | |
while (true) { | |
synchronized (this) { | |
if (isSet) { | |
System.out.println(" take it and make it false"); | |
isSet = false; | |
notify(); | |
} else { | |
wait(); | |
} | |
} | |
} | |
} | |
public static void main(String... strings) { | |
final CacheImplementation mco = new CacheImplementation(); | |
new Thread(new Runnable() { | |
@Override | |
public void run() { | |
try { | |
mco.get(); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
} | |
}).start(); | |
new Thread(new Runnable() { | |
@Override | |
public void run() { | |
try { | |
mco.put("put"); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
} | |
}).start(); | |
} | |
} |
Here queue is used to just check the size right ?. if so we can use linked hash map which can be of fixed size..
ReplyDeleteYes we can use, but the issue is it is not threadsafe. Ideally we can use concurrentlinkedhashmap [https://code.google.com/p/concurrentlinkedhashmap/] which is provided by google library.
ReplyDeleteCan we not use LinkedHashMap alone, ConcurrentLinkedQueue may be creating extra Objects.
ReplyDeleteNow days guava cache is most popular.For this we use google guava library and make cache in easy steps.see fully example
ReplyDeletehttp://www.javaproficiency.com/2015/05/guava-cache-memory-example.html
It's not an LRU cache, LRU means least recently *used* not least recently put. Also I can't see how you "concurrent" version is thread safe. You can have very odd behavior if multiple threads put some value for the same key.
ReplyDeletePlease note: There's a serious bug in JDK 8, which leads to memory issues and high CPU usage, because threads are stuck in ConcurrentLinkedQueue#remove.
ReplyDeletehttps://bugs.openjdk.java.net/browse/JDK-8054446
My workaround is to use a ConcurrentLinkedDeque instead.
Really something Grate in this article Thanks for sharing this. We are providing Online Training Classes. After reading this slightly I am changed my way of introduction about my training to people.
ReplyDeleteBest Linux training in Noida
Linux Training Institute in Noida
Shell Scripting Training Institute in Noida