From c8ad1f7f99cf66a736b0a4f0c4a0493d0d5c321c Mon Sep 17 00:00:00 2001 From: Zach Liebowitz Date: Mon, 27 Jul 2026 19:53:28 -0400 Subject: [PATCH] Fix StringLocker behavior. --- .../src/main/java/ucar/nc2/StringLocker.java | 18 +++----- .../test/java/ucar/nc2/StringLockerTest.java | 46 +++++++++++++++++++ 2 files changed, 53 insertions(+), 11 deletions(-) create mode 100644 cdm/core/src/test/java/ucar/nc2/StringLockerTest.java diff --git a/cdm/core/src/main/java/ucar/nc2/StringLocker.java b/cdm/core/src/main/java/ucar/nc2/StringLocker.java index 5fba06b13a..6f90f77ff1 100644 --- a/cdm/core/src/main/java/ucar/nc2/StringLocker.java +++ b/cdm/core/src/main/java/ucar/nc2/StringLocker.java @@ -1,8 +1,7 @@ package ucar.nc2; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; +import java.util.concurrent.ConcurrentSkipListSet; /** * A list of strings that only allows one thread to use any given value at the same time. @@ -13,13 +12,11 @@ @Deprecated public class StringLocker { - private List stringList = Collections.synchronizedList(new ArrayList<>()); - private boolean waiting; + private final Set stringSet = new ConcurrentSkipListSet<>(); public synchronized void control(String item) { // If the string is in use by another thread then wait() for the other thread - waiting = stringList.contains(item); - while (waiting) { + while (stringSet.contains(item)) { try { wait(); } catch (InterruptedException e) { @@ -27,18 +24,17 @@ public synchronized void control(String item) { } } // Finished waiting so the thread can have the string - stringList.add(item); + stringSet.add(item); } public synchronized void release(String item) { // Tell StringLocker the thread is done with the string - stringList.remove(item); - waiting = false; + stringSet.remove(item); notifyAll(); } public String toString() { - return stringList.toString(); + return stringSet.toString(); } } diff --git a/cdm/core/src/test/java/ucar/nc2/StringLockerTest.java b/cdm/core/src/test/java/ucar/nc2/StringLockerTest.java new file mode 100644 index 0000000000..3c3d5781b5 --- /dev/null +++ b/cdm/core/src/test/java/ucar/nc2/StringLockerTest.java @@ -0,0 +1,46 @@ +package ucar.nc2; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runners.model.TestTimedOutException; + +public class StringLockerTest { + @Test + public void testNonconflicting() { + StringLocker locker = new StringLocker(); + locker.control("first"); + locker.control("second"); + locker.release("first"); + locker.release("second"); + } + + + @Test + public void testConflicting() { + Thread t = new Thread(() -> { + StringLocker locker = new StringLocker(); + locker.control("first"); + locker.control("second"); + locker.release("second"); + locker.control("first"); + Assert.fail("first has been locked twice"); + }); + t.start(); + try { + t.join(50l); + } catch (InterruptedException e) { + // try to abort. + t.interrupt(); + // pass + } + } + + @Test + public void testNonconflictingOtherOrder() { + StringLocker locker = new StringLocker(); + locker.control("first"); + locker.control("second"); + locker.release("second"); + locker.release("first"); + } +}