Class LinearizableLatch

java.lang.Object
com.loomcache.server.cp.LinearizableLatch

public final class LinearizableLatch extends Object
Distributed countdown latch for synchronizing multiple threads on a shared counter.

Purpose: A countdown latch allows threads to wait until a count reaches zero. One thread can decrement the count, and other threads block on await() until the count is zero. This is useful for coordinating parallel work.

Semantics:

  • A latch is initialized with a count (e.g., 3 tasks).
  • Each task calls countDown() when complete, decrementing the count.
  • Threads call await() to block until the count reaches zero.
  • Once the count reaches zero, all awaiting threads are released and subsequent awaits return immediately.

Thread Safety: This class is thread-safe. Multiple threads can safely await and decrement the count concurrently. Uses ReentrantLock with Condition instead of synchronized to avoid pinning virtual threads.

Example:

Logger log = LoggerFactory.getLogger("download-tasks");
LinearizableLatch latch = subsystem.getCountDownLatch("download-tasks", 3);
ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 0; i invalid input: '<' 3; i++) {
    executor.submit(() -> {
        downloadFile();
        latch.countDown(); // Signal task complete
    });
}
latch.await(); // Wait for all tasks to complete
log.info("All downloads complete");
Since:
1.0
  • Constructor Details

    • LinearizableLatch

      public LinearizableLatch(String latchName, long initialCount)
      Creates a new LinearizableLatch with the given initial count.
      Parameters:
      latchName - the name of this latch (must not be null or empty)
      initialCount - the initial count (must be non-negative)
      Throws:
      NullPointerException - if latchName is null
      IllegalArgumentException - if latchName is empty or initialCount invalid input: '<' 0
  • Method Details

    • await

      public void await() throws InterruptedException
      Waits until the count reaches zero.

      If the count is already zero, this method returns immediately. If interrupted, throws InterruptedException.

      Throws:
      InterruptedException - if the current thread is interrupted
    • await

      public boolean await(long timeout, TimeUnit unit) throws InterruptedException
      Waits until the count reaches zero or the timeout expires.
      Parameters:
      timeout - the maximum time to wait
      unit - the time unit of the timeout
      Returns:
      true if the count reached zero, false if timeout expired
      Throws:
      InterruptedException - if the current thread is interrupted
      NullPointerException - if unit is null
    • countDown

      public void countDown()
      Decrements the count by one.

      If the count reaches zero, all awaiting threads are released. If the count is already zero, this method has no effect.

    • getCount

      public long getCount()
      Gets the current count.
      Returns:
      the current count (0 or greater)
    • trySetCount

      public boolean trySetCount(long newCount)
      Attempts to set the count to a new value.

      This operation is useful for dynamically adjusting the latch count (e.g., if more tasks are added). This will create a new internal latch if the count changes.

      Parameters:
      newCount - the new count (must be non-negative)
      Returns:
      true if the count was changed, false if it was already at or below the new count
      Throws:
      IllegalArgumentException - if newCount invalid input: '<' 0
    • isCountedDown

      public boolean isCountedDown()
      Checks if the latch has counted down to zero.
      Returns:
      true if the count is zero