This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-jcs.git
commit 41523a348ea0fde40e9e749c88d9a7e0ac1352ee Author: Thomas Vandahl <[email protected]> AuthorDate: Mon Sep 14 16:35:48 2026 +0200 Introduce locking for DoubleLinkedList --- .../jcs4/utils/struct/DoubleLinkedList.java | 182 +++++++++++++++------ .../utils/struct/DoubleLinkedListUnitTest.java | 4 +- 2 files changed, 137 insertions(+), 49 deletions(-) diff --git a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedList.java b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedList.java index 72a28129..950a524d 100644 --- a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedList.java +++ b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedList.java @@ -1,6 +1,8 @@ package org.apache.commons.jcs4.utils.struct; import java.util.Iterator; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; /* * Licensed to the Apache Software Foundation (ASF) under one @@ -60,6 +62,9 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> /** Record size to avoid having to iterate */ private int size; + /** The lock */ + private final Lock lock; + /** LRU double linked list head node */ private T first; @@ -75,6 +80,7 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> this.last = (T) new DoubleLinkedListNode(); this.first.next = this.last; this.last.prev = this.first; + this.lock = new ReentrantLock(); } /** @@ -84,11 +90,19 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> */ public void addFirst(final T me) { - me.prev = first; - me.next = first.next; - first.next.prev = me; - first.next = me; - size++; + lock.lock(); + try + { + me.prev = first; + me.next = first.next; + first.next.prev = me; + first.next = me; + size++; + } + finally + { + lock.unlock(); + } } /** @@ -98,11 +112,19 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> */ public void addLast(final T me) { - me.next = last; - me.prev = last.prev; - last.prev.next = me; - last.prev = me; - size++; + lock.lock(); + try + { + me.next = last; + me.prev = last.prev; + last.prev.next = me; + last.prev = me; + size++; + } + finally + { + lock.unlock(); + } } // /////////////////////////////////////////////////////////////////// @@ -128,8 +150,9 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> */ public T getFirst() { - log.debug( "returning first node" ); - return (T) first.next; + log.debug("returning first node"); + DoubleLinkedListNode f = first.next; + return (T) (f == last ? null : f); } /** @@ -139,8 +162,9 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> */ public T getLast() { - log.debug( "returning last node" ); - return (T) last.prev; + log.debug("returning last node"); + DoubleLinkedListNode l = last.prev; + return (T) (l == first ? null : l); } /** @@ -150,15 +174,25 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> */ public void makeFirst(final T ln) { - if (ln.prev != null) + lock.lock(); + try + { + if (ln.prev != null && ln.next != null) + { + ln.prev.next = ln.next; + ln.next.prev = ln.prev; + size--; + } + ln.prev = first; + ln.next = first.next; + first.next.prev = ln; + first.next = ln; + size++; + } + finally { - ln.prev.next = ln.next; - ln.next.prev = ln.prev; + lock.unlock(); } - ln.prev = first; - ln.next = first.next; - first.next.prev = ln; - first.next = ln; } /** @@ -168,15 +202,25 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> */ public void makeLast(final T ln) { - if (ln.prev != null) + lock.lock(); + try + { + if (ln.prev != null && ln.next != null) + { + ln.prev.next = ln.next; + ln.next.prev = ln.prev; + size--; + } + ln.next = last; + ln.prev = last.prev; + last.prev.next = ln; + last.prev = ln; + size++; + } + finally { - ln.prev.next = ln.next; - ln.next.prev = ln.prev; + lock.unlock(); } - ln.next = last; - ln.prev = last.prev; - last.prev.next = ln; - last.prev = ln; } /** @@ -188,10 +232,21 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> public boolean remove(final T me) { log.debug("removing node"); - me.prev.next = me.next; - me.next.prev = me.prev; - me.prev = me.next = null; - size--; + lock.lock(); + try + { + if (me.prev != null && me.next != null) + { + me.prev.next = me.next; + me.next.prev = me.prev; + me.prev = me.next = null; + size--; + } + } + finally + { + lock.unlock(); + } return true; } @@ -201,17 +256,25 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> */ public void removeAll() { - T me = getFirst(); - while (me.next != null) + DoubleLinkedListNode me = getFirst(); + lock.lock(); + try + { + while (me != null && me.next != null) + { + DoubleLinkedListNode toRemove = me; + me = me.next; + toRemove.prev = null; + toRemove.next = null; + } + first.next = last; + last.prev = first; + size = 0; + } + finally { - T toRemove = me; - me = (T) me.next; - toRemove.prev = null; - toRemove.next = null; + lock.unlock(); } - first.next = last; - last.prev = first; - size = 0; } /** @@ -222,12 +285,21 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> public T removeLast() { log.debug("removing last node"); - final T temp = (T) last.prev; - if (last != first) + lock.lock(); + try + { + final T temp = (T) last.prev; + if (temp != first) + { + remove(temp); + return temp; + } + } + finally { - remove(temp); - return temp; + lock.unlock(); } + return null; } @@ -256,13 +328,29 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> @Override public boolean hasNext() { - return runner.next != null && runner.next != last; + lock.lock(); + try + { + return runner.next != null && runner.next != last; + } + finally + { + lock.unlock(); + } } @Override public T next() { - runner = (T) runner.next; + lock.lock(); + try + { + runner = (T) runner.next; + } + finally + { + lock.unlock(); + } return runner; } }; diff --git a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedListUnitTest.java b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedListUnitTest.java index f9840050..dd1be24a 100644 --- a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedListUnitTest.java +++ b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedListUnitTest.java @@ -181,8 +181,8 @@ class DoubleLinkedListUnitTest // VERIFY assertEquals( 0, list.size(), "Wrong size" ); - assertEquals( list.getFirst().prev, list.getLast(), "Wrong last" ); - assertEquals( list.getLast().next, list.getFirst(), "Wrong first" ); + assertNull( list.getLast(), "Wrong last" ); + assertNull( list.getFirst(), "Wrong first" ); assertNull(node1.next, "node1.next should be null"); assertNull(node1.prev, "node1.prev should be null"); assertNull(node2.next, "node2.next should be null");
