BAEL-4464 : how to implement LRU-Cache in java codes added (#11036)
* BAEL-4464 : how to implement LRU-Cache in java codes added * BAEL-4464 : how to implement LRU-Cache in java codes added - package named fixed * BAEL-4464 : how to implement LRU-Cache in java codes added - package named changed * BAEL-4464 : how to implement LRU-Cache in java codes added - unitTest fixed
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
package com.baeldung.lrucache;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
public class LRUCache<K, V> implements Cache<K, V> {
|
||||
private int size;
|
||||
private Map<K, LinkedListNode<CacheElement<K, V>>> linkedListNodeMap;
|
||||
private DoublyLinkedList<CacheElement<K, V>> doublyLinkedList;
|
||||
private ReentrantReadWriteLock.ReadLock readLock;
|
||||
private ReentrantReadWriteLock.WriteLock writeLock;
|
||||
|
||||
public LRUCache(int size) {
|
||||
this.size = size;
|
||||
this.linkedListNodeMap = new Hashtable<>(size);
|
||||
this.doublyLinkedList = new DoublyLinkedList<>();
|
||||
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
this.readLock = lock.readLock();
|
||||
this.writeLock = lock.writeLock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean put(K key, V value) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
CacheElement<K, V> item = new CacheElement<K, V>(key, value);
|
||||
LinkedListNode<CacheElement<K, V>> newNode;
|
||||
if (this.linkedListNodeMap.containsKey(key)) {
|
||||
LinkedListNode<CacheElement<K, V>> node = this.linkedListNodeMap.get(key);
|
||||
newNode = doublyLinkedList.updateAndMoveToFront(node, item);
|
||||
} else {
|
||||
if (this.size() >= this.size) {
|
||||
this.evictElement();
|
||||
}
|
||||
newNode = this.doublyLinkedList.add(item);
|
||||
}
|
||||
if (newNode.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
this.linkedListNodeMap.put(key, newNode);
|
||||
return true;
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<V> get(K key) {
|
||||
readLock.lock();
|
||||
try {
|
||||
LinkedListNode<CacheElement<K, V>> linkedListNode = this.linkedListNodeMap.get(key);
|
||||
if (linkedListNode != null && !linkedListNode.isEmpty()) {
|
||||
linkedListNodeMap.put(key, this.doublyLinkedList.moveToFront(linkedListNode));
|
||||
return Optional.of(linkedListNode.getElement().getValue());
|
||||
}
|
||||
return Optional.empty();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return doublyLinkedList.size();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
writeLock.lock();
|
||||
try {
|
||||
linkedListNodeMap.clear();
|
||||
doublyLinkedList.clear();
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean evictElement() {
|
||||
writeLock.lock();
|
||||
try {
|
||||
LinkedListNode<CacheElement<K, V>> linkedListNode = doublyLinkedList.removeTail();
|
||||
if (linkedListNode.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
linkedListNodeMap.remove(linkedListNode.getElement().getKey());
|
||||
return true;
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user