* 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

* BAEL-4464 : issues 4,5 fixed.

* fixed some issues in BAEL-4464
This commit is contained in:
Arash Ariani 2021-07-20 09:51:36 +04:30 committed by GitHub
parent b9571f02f5
commit 66b40ed662
2 changed files with 34 additions and 44 deletions

View File

@ -10,67 +10,62 @@ public class DoublyLinkedList<T> {
private LinkedListNode<T> head; private LinkedListNode<T> head;
private LinkedListNode<T> tail; private LinkedListNode<T> tail;
private AtomicInteger size; private AtomicInteger size;
private ReentrantReadWriteLock.ReadLock readLock; private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private ReentrantReadWriteLock.WriteLock writeLock;
public DoublyLinkedList() { public DoublyLinkedList() {
this.dummyNode = new DummyNode<T>(this); this.dummyNode = new DummyNode<T>(this);
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
readLock = lock.readLock();
writeLock = lock.writeLock();
clear(); clear();
} }
public void clear() { public void clear() {
writeLock.lock(); this.lock.writeLock().lock();
try { try {
head = dummyNode; head = dummyNode;
tail = dummyNode; tail = dummyNode;
size = new AtomicInteger(0); size = new AtomicInteger(0);
} finally { } finally {
writeLock.unlock(); this.lock.writeLock().unlock();
} }
} }
public int size() { public int size() {
readLock.lock(); this.lock.readLock().lock();
try { try {
return size.get(); return size.get();
} finally { } finally {
readLock.unlock(); this.lock.readLock().unlock();
} }
} }
public boolean isEmpty() { public boolean isEmpty() {
readLock.lock(); this.lock.readLock().lock();
try { try {
return head.isEmpty(); return head.isEmpty();
} finally { } finally {
readLock.unlock(); this.lock.readLock().unlock();
} }
} }
public boolean contains(T value) { public boolean contains(T value) {
readLock.lock(); this.lock.readLock().lock();
try { try {
return search(value).hasElement(); return search(value).hasElement();
} finally { } finally {
readLock.unlock(); this.lock.readLock().unlock();
} }
} }
public LinkedListNode<T> search(T value) { public LinkedListNode<T> search(T value) {
readLock.lock(); this.lock.readLock().lock();
try { try {
return head.search(value); return head.search(value);
} finally { } finally {
readLock.unlock(); this.lock.readLock().unlock();
} }
} }
public LinkedListNode<T> add(T value) { public LinkedListNode<T> add(T value) {
writeLock.lock(); this.lock.writeLock().lock();
try { try {
head = new Node<T>(value, head, this); head = new Node<T>(value, head, this);
if (tail.isEmpty()) { if (tail.isEmpty()) {
@ -79,12 +74,12 @@ public class DoublyLinkedList<T> {
size.incrementAndGet(); size.incrementAndGet();
return head; return head;
} finally { } finally {
writeLock.unlock(); this.lock.writeLock().unlock();
} }
} }
public boolean addAll(Collection<T> values) { public boolean addAll(Collection<T> values) {
writeLock.lock(); this.lock.writeLock().lock();
try { try {
for (T value : values) { for (T value : values) {
if (add(value).isEmpty()) { if (add(value).isEmpty()) {
@ -93,12 +88,12 @@ public class DoublyLinkedList<T> {
} }
return true; return true;
} finally { } finally {
writeLock.unlock(); this.lock.writeLock().unlock();
} }
} }
public LinkedListNode<T> remove(T value) { public LinkedListNode<T> remove(T value) {
writeLock.lock(); this.lock.writeLock().lock();
try { try {
LinkedListNode<T> linkedListNode = head.search(value); LinkedListNode<T> linkedListNode = head.search(value);
if (!linkedListNode.isEmpty()) { if (!linkedListNode.isEmpty()) {
@ -113,12 +108,12 @@ public class DoublyLinkedList<T> {
} }
return linkedListNode; return linkedListNode;
} finally { } finally {
writeLock.unlock(); this.lock.writeLock().unlock();
} }
} }
public LinkedListNode<T> removeTail() { public LinkedListNode<T> removeTail() {
writeLock.lock(); this.lock.writeLock().lock();
try { try {
LinkedListNode<T> oldTail = tail; LinkedListNode<T> oldTail = tail;
if (oldTail == head) { if (oldTail == head) {
@ -132,7 +127,7 @@ public class DoublyLinkedList<T> {
} }
return oldTail; return oldTail;
} finally { } finally {
writeLock.unlock(); this.lock.writeLock().unlock();
} }
} }
@ -141,7 +136,7 @@ public class DoublyLinkedList<T> {
} }
public LinkedListNode<T> updateAndMoveToFront(LinkedListNode<T> node, T newValue) { public LinkedListNode<T> updateAndMoveToFront(LinkedListNode<T> node, T newValue) {
writeLock.lock(); this.lock.writeLock().lock();
try { try {
if (node.isEmpty() || (this != (node.getListReference()))) { if (node.isEmpty() || (this != (node.getListReference()))) {
return dummyNode; return dummyNode;
@ -150,7 +145,7 @@ public class DoublyLinkedList<T> {
add(newValue); add(newValue);
return head; return head;
} finally { } finally {
writeLock.unlock(); this.lock.writeLock().unlock();
} }
} }

View File

@ -1,6 +1,5 @@
package com.baeldung.lrucache; package com.baeldung.lrucache;
import java.util.Hashtable;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -10,21 +9,17 @@ public class LRUCache<K, V> implements Cache<K, V> {
private int size; private int size;
private Map<K, LinkedListNode<CacheElement<K, V>>> linkedListNodeMap; private Map<K, LinkedListNode<CacheElement<K, V>>> linkedListNodeMap;
private DoublyLinkedList<CacheElement<K, V>> doublyLinkedList; private DoublyLinkedList<CacheElement<K, V>> doublyLinkedList;
private ReentrantReadWriteLock.ReadLock readLock; private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private ReentrantReadWriteLock.WriteLock writeLock;
public LRUCache(int size) { public LRUCache(int size) {
this.size = size; this.size = size;
this.linkedListNodeMap = new Hashtable<>(size); this.linkedListNodeMap = new ConcurrentHashMap<>(size);
this.doublyLinkedList = new DoublyLinkedList<>(); this.doublyLinkedList = new DoublyLinkedList<>();
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
this.readLock = lock.readLock();
this.writeLock = lock.writeLock();
} }
@Override @Override
public boolean put(K key, V value) { public boolean put(K key, V value) {
writeLock.lock(); this.lock.writeLock().lock();
try { try {
CacheElement<K, V> item = new CacheElement<K, V>(key, value); CacheElement<K, V> item = new CacheElement<K, V>(key, value);
LinkedListNode<CacheElement<K, V>> newNode; LinkedListNode<CacheElement<K, V>> newNode;
@ -43,13 +38,13 @@ public class LRUCache<K, V> implements Cache<K, V> {
this.linkedListNodeMap.put(key, newNode); this.linkedListNodeMap.put(key, newNode);
return true; return true;
} finally { } finally {
writeLock.unlock(); this.lock.writeLock().unlock();
} }
} }
@Override @Override
public Optional<V> get(K key) { public Optional<V> get(K key) {
readLock.lock(); this.lock.readLock().lock();
try { try {
LinkedListNode<CacheElement<K, V>> linkedListNode = this.linkedListNodeMap.get(key); LinkedListNode<CacheElement<K, V>> linkedListNode = this.linkedListNodeMap.get(key);
if (linkedListNode != null && !linkedListNode.isEmpty()) { if (linkedListNode != null && !linkedListNode.isEmpty()) {
@ -58,17 +53,17 @@ public class LRUCache<K, V> implements Cache<K, V> {
} }
return Optional.empty(); return Optional.empty();
} finally { } finally {
readLock.unlock(); this.lock.readLock().unlock();
} }
} }
@Override @Override
public int size() { public int size() {
readLock.lock(); this.lock.readLock().lock();
try { try {
return doublyLinkedList.size(); return doublyLinkedList.size();
} finally { } finally {
readLock.unlock(); this.lock.readLock().unlock();
} }
} }
@ -79,18 +74,18 @@ public class LRUCache<K, V> implements Cache<K, V> {
@Override @Override
public void clear() { public void clear() {
writeLock.lock(); this.lock.writeLock().lock();
try { try {
linkedListNodeMap.clear(); linkedListNodeMap.clear();
doublyLinkedList.clear(); doublyLinkedList.clear();
} finally { } finally {
writeLock.unlock(); this.lock.writeLock().unlock();
} }
} }
private boolean evictElement() { private boolean evictElement() {
writeLock.lock(); this.lock.writeLock().lock();
try { try {
LinkedListNode<CacheElement<K, V>> linkedListNode = doublyLinkedList.removeTail(); LinkedListNode<CacheElement<K, V>> linkedListNode = doublyLinkedList.removeTail();
if (linkedListNode.isEmpty()) { if (linkedListNode.isEmpty()) {
@ -99,7 +94,7 @@ public class LRUCache<K, V> implements Cache<K, V> {
linkedListNodeMap.remove(linkedListNode.getElement().getKey()); linkedListNodeMap.remove(linkedListNode.getElement().getKey());
return true; return true;
} finally { } finally {
writeLock.unlock(); this.lock.writeLock().unlock();
} }
} }
} }