public abstract class NonBlockingLockManagerWithNewDesign<R extends Comparable<R>> extends Object implements ICounterSetAccess
ResourceQueue
is created for each resource and used to block
operations that are awaiting a lock. When those locks become available,
ready(Runnable)
will be invoked with the task.
The class will use an optional WAITS_FOR
graph to detect
deadlocks if locks are not being pre-declared (and hence deadlocks are
possible).
ready(Runnable)
Modifier and Type | Class and Description |
---|---|
protected static class |
NonBlockingLockManagerWithNewDesign.Counters
Counters for the
NonBlockingLockManagerWithNewDesign . |
static class |
NonBlockingLockManagerWithNewDesign.LockFutureTask<R extends Comparable<R>,T>
FutureTask which executes once it holds its locks. |
protected static class |
NonBlockingLockManagerWithNewDesign.ResourceQueue<R extends Comparable<R>,T extends NonBlockingLockManagerWithNewDesign.LockFutureTask<R,? extends Object>>
Unbounded queue of operations waiting to gain an exclusive lock on a
resource.
|
protected class |
NonBlockingLockManagerWithNewDesign.StatisticsTask
Class for tracking the average queue size of each
ResourceQueue
and various other moving averages for the service as a whole. |
Modifier and Type | Field and Description |
---|---|
protected static org.apache.log4j.Logger |
log |
NonBlockingLockManagerWithNewDesign.StatisticsTask |
statisticsTask
This
Runnable should be submitted to a
ScheduledExecutorService in order to track the average queue size
for each active ResourceQueue and various moving averages
pertaining to the lock service as a whole. |
Constructor and Description |
---|
NonBlockingLockManagerWithNewDesign(int maxConcurrency,
int maxLockTries,
boolean predeclareLocks)
Create a lock manager.
|
Modifier and Type | Method and Description |
---|---|
CounterSet |
getCounters()
Note: You MUST submit
statisticsTask to a
ScheduledExecutorService in order counter values which report
moving averages to be maintained. |
Runnable |
getTaskWithLocks(R[] resource)
Return the task holding all of the specified locks.
|
boolean |
isLockHeldByTask(R lock,
Runnable task)
Return
true if the lock is held by the task at the moment
when it is inspected. |
boolean |
isOpen() |
boolean |
isShutdown() |
boolean |
isTerminated() |
protected abstract void |
ready(Runnable task)
Method invoked when a task is ready to execute holding any locks which it
declared to
submit(Comparable[], Callable) or
submit(Comparable[], Runnable, Object) . |
void |
releaseLocksForTask(R[] resource)
If there is a task holding ALL of the specified locks then its locks are
released.
|
void |
shutdown() |
void |
shutdownNow() |
<T> FutureTask<T> |
submit(R[] resource,
Callable<T> task)
Submit a task for execution.
|
<T> FutureTask<T> |
submit(R[] resource,
Runnable task,
T val)
Variant for a
Runnable target. |
String |
toString() |
protected static final org.apache.log4j.Logger log
public final NonBlockingLockManagerWithNewDesign.StatisticsTask statisticsTask
Runnable
should be submitted to a
ScheduledExecutorService
in order to track the average queue size
for each active ResourceQueue
and various moving averages
pertaining to the lock service as a whole.public NonBlockingLockManagerWithNewDesign(int maxConcurrency, int maxLockTries, boolean predeclareLocks)
true
as deadlocks are
impossible and we do not maintain a WAITS_FOR graph.maxConcurrency
- The maximum multi-programming level (ignored if
predeclareLocks is true
).maxLockTries
- The maximum #of times that a task whose lock requests would
produce a deadlock will be retried. Deadlock is typically
transient but the potential for deadlock can vary depending on
the application. Note that deadlock CAN NOT arise if you are
predeclaring and sorting the lock requests.predeclareLocks
- When true
, operations MUST declare all locks
before they begin to execute. This makes possible several
efficiencies and by sorting the resources in each lock request
into a common order we are able to avoid deadlocks entirely.public CounterSet getCounters()
statisticsTask
to a
ScheduledExecutorService
in order counter values which report
moving averages to be maintained.
Note: A new instance is returned every time. This makes the pattern where the counters are "attached" to a hierarchy work since that has the side-effect of "detaching" them from the returned object.
getCounters
in interface ICounterSetAccess
protected abstract void ready(Runnable task)
submit(Comparable[], Callable)
or
submit(Comparable[], Runnable, Object)
. The implementation will
normally submit the Runnable
to an Executor
. The
Runnable
wraps the original task and the task will automatically
release its locks when it is done executing.
Note: Implementations SHOULD NOT cause the Runnable
to execute in
the caller's thread. That will cause this service to block while the task
is executing. The implementation can safely submit the task to a
ThreadPoolExecutor
whose work queue is a SynchronousQueue
as long as the the ThreadPoolExecutor
has an unbounded pool size.
Another option is to submit the task to a ThreadPoolExecutor
whose work queue is unbounded queue, such as LinkedBlockingQueue
when no queue capacity was specified. The SynchronousQueue
may be
the better choice since the ResourceQueue
s already provide an
unbounded queue and the actual concurrency of the delegate will be
bounded by the #of distinct resources for which tasks are actively
contending for locks. See the discussion on queues at
ThreadPoolExecutor
.
task
- The Callable
or Runnable
wrapped up as a
NonBlockingLockManagerWithNewDesign.LockFutureTask
.public boolean isOpen()
public boolean isShutdown()
public boolean isTerminated()
public void shutdown()
public void shutdownNow()
public <T> FutureTask<T> submit(R[] resource, Callable<T> task)
FutureTask.get()
to await the outcome.resource
- An array of resources whose locks are required to execute the
task.task
- The task to be executed.IllegalArgumentException
- if resource is null
or if any element
of that array is null
.IllegalArgumentException
- if the task is null
.RejectedExecutionException
- if the task can not be queued for execution (including if the
service is not running or if a blocking queue was used and
the queue is at capacity).public <T> FutureTask<T> submit(R[] resource, Runnable task, T val)
Runnable
target.T
- The generic type of the value which will be returned by the
Future
.resource
- The declared locks.task
- The Runnable
target.val
- The value to be returned by the Future
.Future
for that task.IllegalArgumentException
- if resource is null
or if any element
of that array is null
.IllegalArgumentException
- if the task is null
.RejectedExecutionException
- if the task can not be queued for execution (including if the
service is not running or if a blocking queue was used and
the queue is at capacity).public final void releaseLocksForTask(R[] resource)
Runnable.run()
is finished.resource[]
- The declared locks for the task.IllegalStateException
- if there is no task which holds all the declared locks.public Runnable getTaskWithLocks(R[] resource)
resource
- The locks.null
iff there is no such task.public boolean isLockHeldByTask(R lock, Runnable task)
true
if the lock is held by the task at the moment
when it is inspected.lock
- The lock.task
- The task.true
if the lock was held by that task.Copyright © 2006–2019 SYSTAP, LLC DBA Blazegraph. All rights reserved.