All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.debezium.util.VariableLatch Maven / Gradle / Ivy

/*
 * Based on java.util.concurrent.CountDownLatch, which was
 * Written by Doug Lea with assistance from members of JCP JSR-166
 * Expert Group and released to the public domain, as explained at
 * http://creativecommons.org/publicdomain/zero/1.0/
 *
 * Any changes relative to CountDownLatch are also released to the
 * public domain, as explained at
 * http://creativecommons.org/publicdomain/zero/1.0/
 */
package io.debezium.util;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

import io.debezium.annotation.ThreadSafe;

/**
 * A latch that works similarly to {@link CountDownLatch} except that it can also increase the count dynamically.
 */
@ThreadSafe
public class VariableLatch {

    /**
     * Create a new variable latch.
     *
     * @return the variable latch; never null
     */
    public static VariableLatch create() {
        return create(0);
    }

    /**
     * Create a new variable latch.
     *
     * @param initialValue the initial number of latches
     * @return the variable latch; never null
     */
    public static VariableLatch create(int initialValue) {
        return new VariableLatch(initialValue);
    }

    /**
     * Synchronization control For CountDownLatch.
     * Uses AQS state to represent count.
     */
    private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;

        Sync(int count) {
            setState(count);
        }

        int getCount() {
            return getState();
        }

        @Override
        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }

        @Override
        protected boolean tryReleaseShared(int releases) {
            // Increment or decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == 0 && releases >= 0) {
                    return false;
                }
                int nextc = c - releases;
                if (nextc < 0) {
                    nextc = 0;
                }
                if (compareAndSetState(c, nextc)) {
                    return nextc == 0;
                }
            }
        }
    }

    private final Sync sync;

    /**
     * Constructs a {@code CountDownLatch} initialized with the given count.
     *
     * @param count the number of times {@link #countDown} must be invoked
     *            before threads can pass through {@link #await}
     * @throws IllegalArgumentException if {@code count} is negative
     */
    public VariableLatch(int count) {
        if (count < 0) {
            throw new IllegalArgumentException("count < 0");
        }
        this.sync = new Sync(count);
    }

    /**
     * Causes the current thread to wait until the latch has counted down to
     * zero, unless the thread is {@linkplain Thread#interrupt interrupted}.
     *
     * 

* If the current count is zero then this method returns immediately. * *

* If the current count is greater than zero then the current thread becomes disabled for thread scheduling purposes and lies * dormant until one of two things happen: *

    *
  • The count reaches zero due to invocations of the {@link #countDown} method; or *
  • Some other thread {@linkplain Thread#interrupt interrupts} the current thread. *
* *

* If the current thread: *

    *
  • has its interrupted status set on entry to this method; or *
  • is {@linkplain Thread#interrupt interrupted} while waiting, *
* then {@link InterruptedException} is thrown and the current thread's interrupted status is cleared. * * @throws InterruptedException if the current thread is interrupted * while waiting */ public void await() throws InterruptedException { sync.acquireSharedInterruptibly(1); } /** * Causes the current thread to wait until the latch has counted down to * zero, unless the thread is {@linkplain Thread#interrupt interrupted}, * or the specified waiting time elapses. * *

* If the current count is zero then this method returns immediately with the value {@code true}. * *

* If the current count is greater than zero then the current thread becomes disabled for thread scheduling purposes and lies * dormant until one of three things happen: *

    *
  • The count reaches zero due to invocations of the {@link #countDown} method; or *
  • Some other thread {@linkplain Thread#interrupt interrupts} the current thread; or *
  • The specified waiting time elapses. *
* *

* If the count reaches zero then the method returns with the value {@code true}. * *

* If the current thread: *

    *
  • has its interrupted status set on entry to this method; or *
  • is {@linkplain Thread#interrupt interrupted} while waiting, *
* then {@link InterruptedException} is thrown and the current thread's interrupted status is cleared. * *

* If the specified waiting time elapses then the value {@code false} is returned. If the time is less than or equal to zero, * the method will not wait at all. * * @param timeout the maximum time to wait * @param unit the time unit of the {@code timeout} argument * @return {@code true} if the count reached zero and {@code false} if the waiting time elapsed before the count reached zero * @throws InterruptedException if the current thread is interrupted * while waiting */ public boolean await(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); } /** * Decrements the count of the latch, releasing all waiting threads if the count reaches zero. * *

* If the current count is greater than zero then it is decremented. If the new count is zero then all waiting threads are * re-enabled for thread scheduling purposes. * *

* If the current count equals zero then nothing happens. */ public void countDown() { sync.releaseShared(1); } /** * Decrements the count of the latch, releasing all waiting threads if the count reaches zero. * *

* If the current count is greater than zero then it is decremented. If the new count is zero then all waiting threads are * re-enabled for thread scheduling purposes. * *

* If the current count equals zero then nothing happens. * * @param count the number of counts to decrease */ public void countDown(int count) { sync.releaseShared(1 * (Math.abs(count))); } /** * Increments the count of the latch by one. */ public void countUp() { sync.releaseShared(-1); } /** * Increments the count of the latch by a positive number. * * @param count the number of counts to increase */ public void countUp(int count) { sync.releaseShared(-1 * (Math.abs(count))); } /** * Returns the current count. * *

* This method is typically used for debugging and testing purposes. * * @return the current count */ public long getCount() { return sync.getCount(); } /** * Returns a string identifying this latch, as well as its state. * The state, in brackets, includes the String {@code "Count ="} followed by the current count. * * @return a string identifying this latch, as well as its state */ @Override public String toString() { return super.toString() + "[Count = " + sync.getCount() + "]"; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy