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

com.rabbitmq.jms.util.EntryExitManager Maven / Gradle / Ivy

There is a newer version: 3.4.0
Show newest version
/* Copyright (c) 2013-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. */
package com.rabbitmq.jms.util;

import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.jms.client.Completion;

/**
 * Manages threads entering and exiting a notional region. Entry is controlled by a gate, and exit is signalled by
 * {@link Completion}. Can block threads entering, abort waiting threads and wait for threads which have entered to exit.
 * 

* When the gate is open, threads are not prevented from entering. When the gate is closed, threads will block on * {@link #enter enter(...)}, until the gate is opened (by some other thread). *

*

* Threads which enter the region must leave it by calling {@link #exit()}. This will signal the exit of the thread. The * manager offers a method {@link #waitToClear waitToClear(...)} which will block * until all the currently entered threads have exited the region. Threads which enter during {@link #waitToClear} are not * detected. *

*
*
{@link #closeGate()}
*
will close the gate to all threads,
*
{@link #openGate()}
*
will open the gate, unblocking all waiting threads,
*
{@link #enter enter(...)}
*
will allow the calling thread to enter the region, or block if the gate is closed,
*
{@link #exit()}
*
will signal the calling thread to exit the region,
*
{@link #waitToClear waitToClear(...)}
*
will block until all the threads currently in the region have exited,
*
{@link #abortWaiters()}
*
will reject all waiting threads with an AbortedException.
*
*/ public class EntryExitManager { private final WaiterGate gate; private final Queue entered = new ConcurrentLinkedQueue(); private ThreadLocal threadCompletion = new ThreadLocal(); private void registerEntry() { Completion comp = new Completion(); this.threadCompletion.set(comp); // thread-local this.entered.add(comp); } /** * Create an EntryExitManager, initially closed. */ public EntryExitManager() { this.gate = new WaiterGate(false) { @Override public void onEntry() { /*register on entry*/ EntryExitManager.this.registerEntry();} @Override public void onAbort() { /*noop*/ } }; } /** * Is the gate closed? * @return true if the gate is closed, false otherwise. */ public boolean isClosed() { return !gate.isOpen(); } /** * Close the gate, if allowed, so subsequent enter()ing threads will block. * @return true in all cases. */ public boolean closeGate() { gate.close(); return true; } /** * Opens the gate and wakes up all waiting threads. Does not block. * @return true in all cases. */ public boolean openGate() { gate.open(); return true; } /** * Returns true immediately if the gate is open. * Otherwise if the gate is closed the thread blocks until one of the following occurs: *
*
gate is opened (by another thread);
*
timeout expires before gate is opened.
*
* @param timeout the time to wait for the gate to open. * @param unit the time unit of the timeout argument. * @return false if timeout was reached before gate opens; true if gate is open or opens while we are waiting. * @throws InterruptedException if the callers thread is interrupted while waiting. * @throws AbortedException if this thread is aborted by a stop() or close() while waiting. */ public boolean enter(long timeout, TimeUnit unit) throws InterruptedException, AbortedException { return enter(new TimeTracker(timeout, unit)); } /** * Returns true immediately if the gate is open. * Otherwise if the gate is closed the thread blocks until one of the following occurs: *
*
gate is opened (by another thread);
*
timeout expires before gate is opened.
*
* @param tt the time tracker used to wait for the gate to open. * @return false if timeout was reached before gate opens; true if gate is open or opens while we are waiting. * @throws InterruptedException if the callers thread is interrupted while waiting. * @throws AbortedException if this thread is aborted by a stop() or close() while waiting. */ public boolean enter(TimeTracker tt) throws InterruptedException, AbortedException { return gate.waitForOpen(tt); } /** * This thread is exiting the region. Must be called eventually by the thread that entered the region. */ public void exit() { Completion comp = this.threadCompletion.get(); // this thread's completion object if (comp != null) { comp.setComplete(); this.entered.remove(comp); } } /** * Wait for current threads to exit region. * @param timeout max time to wait in units. * @param unit of time measurement for timeout. * @return true if they all exited in time, false otherwise. * @throws InterruptedException if thread is interrupted and is waiting. */ public boolean waitToClear(long timeout, TimeUnit unit) throws InterruptedException { return waitToClear(new TimeTracker(timeout, unit)); } /** * Wait for current threads to exit region. * @param tt timeout tracker. * @return true if they all exited in time, false otherwise. * @throws InterruptedException if thread is interrupted and is waiting. */ public boolean waitToClear(TimeTracker tt) throws InterruptedException { List comps = new LinkedList(this.entered); if (comps.isEmpty()) return true; // nothing to wait for for (Completion c : comps) { try { if (tt.timedOut()) return false; c.waitUntilComplete(tt); } catch (TimeoutException unused) { return false; // we ran out of time } } return true; } /** * Abort all threads waiting to enter with an AbortedException. */ public void abortWaiters() { gate.abort(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy