//COPYRIGHT (c) 2007-2010 FARSIGHT SYSTEMS CORPORATION - ALL RIGHTS RESERVED.
package com.farsight_systems.concurrent;
import java.util.concurrent.TimeUnit;
/**
* The public API for an {@code Intersect} that allows participants
* to enter via a particular {@link Pathway} waiting until all other
* {@code Pathway} have released their access. If multiple threads each specify
* the same {@code Pathway} for this {@code Intersect}, then they will
* all share access to the {@code Intersect}. A thread is delayed only
* when it specifies a different {@code Pathway} while the {@code Intersect}
* is being accessed.
*<p/>
* An application that wants to limit the number of concurrent participants
* for a particular {@code Pathway} can provide a wrapper class that combines the
* {@code Intersect} and a {@link Semaphore}.
* See {@link IntersectLimited} for an example class that limits the
* number of concurrent {@code Pathway} accessors.
*<p/>
* Multiple threads may concurrently access a particular {@code Pathway}
* in essentially a read-only manner. Thus, a {@code Pathway} is a
* logical group of read-only accessors (threads). Other groups that
* are represented by other {@code Pathway} instances are synchronized
* with each other by the owning {@code Intersect}. Thus, the threads
* that are currently accessing a particular {@code Pathway} are
* co-operating as a group in a read-only (shared) mode on the logical resource implied
* by the {@code Intersect}, and each group is co-operating with other groups (i.e.,
* other distinct {@code Pathway} instances) in a read-write (exclusive) mode.
*<p/>
* If multiple threads are accessing a specific {@code Pathway} for updating a logical
* resource, then that resource requires its own read-write synchronization
* or locking protocol.
*<p/>
*<pre>
* Intersect
* +-----------+
* | RESOURCE |
* +-----------+
* |
* V
* +----------------+--------+--------+----------------+
* | | | |
* V V V V
* Pathway Pathway Pathway Pathway
* +---------+ +---------+ +---------+ +---------+
* | GROUP | | GROUP | | GROUP | | GROUP |
* +---------+ +---------+ +---------+ +---------+
*</pre>
* Each logical group is read-write (exclusive) synchronized with the other
* groups. Within each group, the threads are read-only (shared) synchronized with
* each other thread in that group. The group that currently has access to the
* resource must provide its own synchronization or locking protocol for its
* multiple threads to update the resource. If there is one thread in the
* group, then no further synchronization or locking is required.
*<p/>
* A {@code Pathway} is <em>owned</em> by a particular {@code Intersect}
* instance and cannot be used by any other {@code Intersect} instance.
*<p/>
* The {@code Pathway} may represent a <em>virtual task</em> acquiring
* exclusive control of the logical resource that is represented by the
* {@code Intersect}. A "dispatcher" thread that is managing the
* <em>virtual task</em> should use the timed access methods with a
* duration of zero to poll for availability. If the {@code Intersect}
* is unavailable, the "dispatcher" thread will mark the <em>virtual task</em>
* as suspended awaiting for the resource, and then dispatch another
* <em>virtual task</em>. Use the {@link IntersectAvailable}
* API to notify the "dispatcher" thread to retry the access request.
*<p/>
* The {@code IntersectAvailable} API is designed for notifying the application
* when the {@code Intersect} is fully released. The call back method is invoked
* by the JVM thread that performed the release. Due to the vagaries of the JVM
* dispatching algorithm, the {@code Intersect} may be re-acquired by any {@code Pathway}
* before the call back method is invoked.
*<p/>
* The application must guarantee that each successful {@link #access(Pathway)}
* is paired with {@link #release(Pathway)} for the same {@link Pathway}.
* <pre>
* private final Intersect intersect = new IntersectLatch();
* private final Pathway pathway = intersect.createPathway();
* private final long duration = 1000000000L; // 1 second
*
* public void doSomething()
* throws InterruptedException
* {
* intersect.access(pathway);
* try
* {
* // the pathway for the intersect is now accessible.
* }
* finally
* {
* intersect.release(pathway);
* }
*
* if(intersect.access(pathway,duration))
* {
* try
* {
* // the pathway for the intersect is now accessible.
* }
* finally
* {
* intersect.release(pathway);
* }
* }
* }
* </pre>
*<p/>
* The {@code Pathway} has convenience methods that omit the {@code Intersect}
* reference to use the implied (owning) {@code Intersect}.
*<pre>
* private final Intersect intersect = new IntersectLatch();
* private final Pathway pathway = intersect.createPathway();
* private final long duration = 1000000000L; // 1 second
*
* public void doSomething()
* throws InterruptedException
* {
* pathway.access();
* try
* {
* // the pathway for the intersect is now accessible.
* }
* finally
* {
* pathway.release();
* }
*
* if(pathway.access(duration))
* {
* try
* {
* // the pathway for the intersect is now accessible.
* }
* finally
* {
* pathway.release();
* }
* }
* }
*</pre>
*<p/>
* The thread that accesses the {@code Intersect} need not be the same
* thread that releases the {@code Intersect} for a particular {@code Pathway}.
*<p/>
* <strong>Memory accesses</strong> occuring in a thread prior to returning
* from releasing an {@code Intersect} with a {@code Pathway}
* <em>happen before</em> memory accesses occuring in another thread subsequent
* to successfully acquiring that {@code Intersect} with a different {@code Pathway}.
*
* @author Jeffrey D. Smith
* @version 2010-MAY-06c JDS
* @version 2010-MAY-05 JDS
* @version 2010-MAY-04 JDS
* @version 2010-MAY-03 JDS
* @version 2010-MAY-01 JDS
* @version 2009-FEB-03 JDS
*/
public interface Intersect
{
/**
* Dispense a new instance of {@link Pathway} for this {@link Intersect}.
* The created {@code Pathway} represents a unique access to the resource
* represented by the {@code Intersect}. The created {@code Pathway} can
* only be used by this instance of {@code Intersect}.
*
* @return A {@code Pathway} for this {@code Intersect}.
*/
public abstract Pathway createPathway();
/**
* Get the current number of reentrant accesses by the specified {@code Pathway}.
*<p/>
* This is the same as calling {@link Pathway#accesses(Intersect) thePathway.accesses(this)}.
*
* @param thePathway The {@code Pathway}.
*
* @return The current number of accesses.
*
* @throws IllegalArgumentException The {@code Pathway} is owned by another {@code Intersect}.
*/
public abstract int accesses(Pathway thePathway);
/**
* Acquire access to the {@code Intersect}, waiting indefinitely
* until available. This
* method will delay subsequent access from other pathways and return
* to the caller when all other pathways are released.
*<p/>
* This is the same as calling {@link Pathway#accessUninterruptibly(Intersect) thePathway.accessUninterruptibly(this)}.
*
* @param thePathway The {@link Pathway} attempting to access the {@code Intersect}.
*
* @throws IllegalArgumentException The {@code Pathway} is owned by another {@code Intersect}.
*/
public abstract void accessUninterruptibly(Pathway thePathway);
/**
* Acquire access to the {@code Intersect}, waiting indefinitely
* until available or throwing {@code InterruptedException}. This
* method will delay subsequent access from other pathways and return
* to the caller when all other pathways are released.
*<p/>
* This is the same as calling {@link Pathway#access(Intersect) thePathway.access(this)}.
*<p/>
* This method is an explicit interrupt point. A pending interrupt
* will be thrown upon entry or when detected while waiting for the
* intersect.
*
* @param thePathway The {@link Pathway} attempting to access the {@code Intersect}.
*
* @throws IllegalArgumentException The {@code Pathway} is owned by another {@code Intersect}.
* @throws InterruptedException The current thread was interrupted before acquiring access.
*/
public abstract void access(Pathway thePathway)
throws InterruptedException;
/**
* Acquire access to the {@code Intersect}, waiting up to the
* specified duration until available or throwing {@code InterruptedException}.
*<p/>
* This is the same as calling {@link Pathway#access(Intersect,long) thePathway.access(this,theDuration)}.
*<p/>
* This method is an explicit interrupt point. A pending interrupt
* will be thrown upon entry or when detected while waiting for the
* intersect.
*
* @param thePathway The {@link Pathway} attempting to access the {@code Intersect}.
* @param theDuration The maximum duration in nanoseconds. Zero means no waiting.
*
* @return {@code true} The {@code Intersect} was acquired before the duration expired.
*
* @throws IllegalArgumentException The {@code Pathway} is owned by another {@code Intersect}.
* @throws InterruptedException The current thread was interrupted before acquiring access.
*/
public abstract boolean access(Pathway thePathway, long theDuration)
throws InterruptedException;
/**
* Acquire access to the {@code Intersect}, waiting up to the
* specified duration until available or throwing {@code InterruptedException}.
*<p/>
* This is the same as calling
* {@link #access(Pathway,long) access(thePathway,theTimeUnit.toNanos(theDuration))}.
*<p/>
* This is the same as calling {@link Pathway#access(Intersect,long,TimeUnit) thePathway.access(this,theDuration,theTimeUnit)}.
*<p/>
* This method is an explicit interrupt point. A pending interrupt
* will be thrown upon entry or when detected while waiting for the
* intersect.
*
* @param thePathway The {@link Pathway} attempting to access the {@code Intersect}.
* @param theDuration The maximum duration to wait. Zero means no waiting.
* @param theTimeUnit The TimeUnit of measure for the duration.
*
* @return {@code true} The {@code Intersect} was acquired before the duration expired.
*
* @throws IllegalArgumentException The {@code Pathway} is owned by another {@code Intersect}.
* @throws InterruptedException The current thread was interrupted before acquiring access.
*/
public abstract boolean access(Pathway thePathway, long theDuration, TimeUnit theTimeUnit)
throws InterruptedException;
/**
* Release access to the {@code Intersect} for the specified {@link Pathway}.
*<p/>
* This is the same as calling {@link Pathway#release(Intersect) thePathway.release(this)}.
*
* @param thePathway The {@link Pathway} that has access to the {@code Intersect}.
*
* @throws IllegalArgumentException The {@code Pathway} is owned by another {@code Intersect}.
* @throws IllegalMonitorStateException The {@code Pathway} has no access to the {@code Intersect}.
*/
public abstract void release(Pathway thePathway);
/**
* Get the {@link IntersectAvailable} reference for this instance.
*
* @return The {@link IntersectAvailable} reference for this instance.
*/
public abstract IntersectAvailable getIntersectAvailable();
/**
* Set the {@link IntersectAvailable} reference for this instance.
*
* @param theIntersectAvailable The next IntersectAvailable reference for this instance.
*
* @return The previous {@link IntersectAvailable} reference for this instance.
*/
public abstract IntersectAvailable setIntersectAvailable(IntersectAvailable theIntersectAvailable);
}
|