Quantcast
Channel: Crunchify
Viewing all articles
Browse latest Browse all 1037

How to Create a Simple In Memory Cache in Java (Lightweight Cache)

$
0
0

Java In Memory Cache Example By Crunchify How to Create a Simple In Memory Cache in Java (Lightweight Cache)

High performance scalable web applications often use a distributed in-memory data cache in front of or in place of robust persistent storage for some tasks. In Java Applications it is very common to use in Memory Cache for better performance. But what is “Cache?”

A cache is an area of local memory that holds a copy of frequently accessed data that is otherwise expensive to get or compute. Examples of such data include a result of a query to a database, a disk file or a report.

Lets look at creating and using a simple thread-safe Java in-memory cache. Here are the characteristic of the program CrunchifyInMemoryCache.java.

  • Items will expire based on a time to live period.
  • Cache will keep most recently used items if you will try to add more items then max specified. (apache common collections has a LRUMap, which, removes the least used entries from a fixed sized map)
  • For the expiration of items we can timestamp the last access and in a separate thread remove the items when the time to live limit is reached. This is nice for reducing memory pressure for applications that have long idle time in between accessing the cached objects.
  • We will also create test class: CrunchifyInMemoryCacheTest.java

Here is a complete package outline..

Crunchify In Memory Cache Example How to Create a Simple In Memory Cache in Java (Lightweight Cache)

Other must read:

CrunchifyInMemoryCache.java

package com.crunchify.tutorials;

import java.util.ArrayList;
import org.apache.commons.collections.MapIterator;
import org.apache.commons.collections.map.LRUMap;

/**
 * @author Crunchify.com
 */

public class CrunchifyInMemoryCache<K, T> {

	private long timeToLive;
	private LRUMap crunchifyCacheMap;

	protected class CrunchifyCacheObject {
		public long lastAccessed = System.currentTimeMillis();
		public T value;

		protected CrunchifyCacheObject(T value) {
			this.value = value;
		}
	}

	public CrunchifyInMemoryCache(long crunchifyTimeToLive, final long crunchifyTimerInterval, int maxItems) {
		this.timeToLive = crunchifyTimeToLive * 1000;

		crunchifyCacheMap = new LRUMap(maxItems);

		if (timeToLive > 0 && crunchifyTimerInterval > 0) {

			Thread t = new Thread(new Runnable() {
				public void run() {
					while (true) {
						try {
							Thread.sleep(crunchifyTimerInterval * 1000);
						} catch (InterruptedException ex) {
						}
						cleanup();
					}
				}
			});

			t.setDaemon(true);
			t.start();
		}
	}

	public void put(K key, T value) {
		synchronized (crunchifyCacheMap) {
			crunchifyCacheMap.put(key, new CrunchifyCacheObject(value));
		}
	}

	@SuppressWarnings("unchecked")
	public T get(K key) {
		synchronized (crunchifyCacheMap) {
			CrunchifyCacheObject c = (CrunchifyCacheObject) crunchifyCacheMap.get(key);

			if (c == null)
				return null;
			else {
				c.lastAccessed = System.currentTimeMillis();
				return c.value;
			}
		}
	}

	public void remove(K key) {
		synchronized (crunchifyCacheMap) {
			crunchifyCacheMap.remove(key);
		}
	}

	public int size() {
		synchronized (crunchifyCacheMap) {
			return crunchifyCacheMap.size();
		}
	}

	@SuppressWarnings("unchecked")
	public void cleanup() {

		long now = System.currentTimeMillis();
		ArrayList<K> deleteKey = null;

		synchronized (crunchifyCacheMap) {
			MapIterator itr = crunchifyCacheMap.mapIterator();

			deleteKey = new ArrayList<K>((crunchifyCacheMap.size() / 2) + 1);
			K key = null;
			CrunchifyCacheObject c = null;

			while (itr.hasNext()) {
				key = (K) itr.next();
				c = (CrunchifyCacheObject) itr.getValue();

				if (c != null && (now > (timeToLive + c.lastAccessed))) {
					deleteKey.add(key);
				}
			}
		}

		for (K key : deleteKey) {
			synchronized (crunchifyCacheMap) {
				crunchifyCacheMap.remove(key);
			}

			Thread.yield();
		}
	}
}

CrunchifyInMemoryCacheTest.java (checkout all comments inside for understanding)

package com.crunchify.tutorials;

import com.crunchify.tutorials.CrunchifyInMemoryCache;

/**
 * @author Crunchify.com
 */

public class CrunchifyInMemoryCacheTest {

	public static void main(String[] args) throws InterruptedException {

		CrunchifyInMemoryCacheTest crunchifyCache = new CrunchifyInMemoryCacheTest();

		System.out.println("\n\n==========Test1: crunchifyTestAddRemoveObjects ==========");
		crunchifyCache.crunchifyTestAddRemoveObjects();
		System.out.println("\n\n==========Test2: crunchifyTestExpiredCacheObjects ==========");
		crunchifyCache.crunchifyTestExpiredCacheObjects();
		System.out.println("\n\n==========Test3: crunchifyTestObjectsCleanupTime ==========");
		crunchifyCache.crunchifyTestObjectsCleanupTime();
	}

	private void crunchifyTestAddRemoveObjects() {

		// Test with timeToLiveInSeconds = 200 seconds
		// timerIntervalInSeconds = 500 seconds
		// maxItems = 6
		CrunchifyInMemoryCache<String, String> cache = new CrunchifyInMemoryCache<String, String>(200, 500, 6);

		cache.put("eBay", "eBay");
		cache.put("Paypal", "Paypal");
		cache.put("Google", "Google");
		cache.put("Microsoft", "Microsoft");
		cache.put("IBM", "IBM");
		cache.put("Facebook", "Facebook");

		System.out.println("6 Cache Object Added.. cache.size(): " + cache.size());
		cache.remove("IBM");
		System.out.println("One object removed.. cache.size(): " + cache.size());

		cache.put("Twitter", "Twitter");
		cache.put("SAP", "SAP");
		System.out.println("Two objects Added but reached maxItems.. cache.size(): " + cache.size());

	}

	private void crunchifyTestExpiredCacheObjects() throws InterruptedException {

		// Test with timeToLiveInSeconds = 1 second
		// timerIntervalInSeconds = 1 second
		// maxItems = 10
		CrunchifyInMemoryCache<String, String> cache = new CrunchifyInMemoryCache<String, String>(1, 1, 10);

		cache.put("eBay", "eBay");
		cache.put("Paypal", "Paypal");
		// Adding 3 seconds sleep.. Both above objects will be removed from
		// Cache because of timeToLiveInSeconds value
		Thread.sleep(3000);

		System.out.println("Two objects are added but reached timeToLive. cache.size(): " + cache.size());

	}

	private void crunchifyTestObjectsCleanupTime() throws InterruptedException {
		int size = 500000;

		// Test with timeToLiveInSeconds = 100 seconds
		// timerIntervalInSeconds = 100 seconds
		// maxItems = 500000

		CrunchifyInMemoryCache<String, String> cache = new CrunchifyInMemoryCache<String, String>(100, 100, 500000);

		for (int i = 0; i < size; i++) {
			String value = Integer.toString(i);
			cache.put(value, value);
		}

		Thread.sleep(200);

		long start = System.currentTimeMillis();
		cache.cleanup();
		double finish = (double) (System.currentTimeMillis() - start) / 1000.0;

		System.out.println("Cleanup times for " + size + " objects are " + finish + " s");

	}
}

Output:

==========Test1: crunchifyTestAddRemoveObjects ==========
6 Cache Object Added.. cache.size(): 6
One object removed.. cache.size(): 5
Two objects Added but reached maxItems.. cache.size(): 6

==========Test2: crunchifyTestExpiredCacheObjects ==========
Two objects are added but reached timeToLive. cache.size(): 0

==========Test3: crunchifyTestObjectsCleanupTime ==========
Cleanup times for 500000 objects are 0.025 s

If you have any of below questions/problems then this simple Cache implementation is for you:

  • caching - Lightweight Java Object cache API
  • caching - Looking for simple Java in-memory cache
  • How to create thread-safe in memory caching?
  • Simple Caching for Java Applications
  • Simple Java Caching System

Cheers…!! Happy Coding..

Arpit..

The post How to Create a Simple In Memory Cache in Java (Lightweight Cache) appeared first on Crunchify.


Viewing all articles
Browse latest Browse all 1037

Trending Articles