return;
// take a snapshot of the current container state.
LinkedList<InstanceWrapper> toOutput = new LinkedList<InstanceWrapper>(instances.values());
Executor executorService = null;
Semaphore taskLock = null;
synchronized(lockForExecutorServiceSetter)
{
executorService = outputExecutorService;
if (executorService != null)
taskLock = new Semaphore(outputConcurrency);
}
// This keeps track of the number of concurrently running
// output tasks so that this method can wait until they're
// all done to return.
//
// It's also used as a condition variable signaling on its
// own state changes.
final AtomicLong numExecutingOutputs = new AtomicLong(0);
// keep going until all of the outputs have been invoked
while (toOutput.size() > 0 && isRunning)
{
for (final Iterator<InstanceWrapper> iter = toOutput.iterator(); iter.hasNext();)
{
final InstanceWrapper wrapper = iter.next();
boolean gotLock = false;
gotLock = wrapper.tryLock();
if (gotLock)
{
// If we've been evicted then we're on our way out
// so don't do anything else with this.
if (wrapper.isEvicted())
{
iter.remove();
wrapper.releaseLock();
continue;
}
final Object instance = wrapper.getInstance(); // only called while holding the lock
final Semaphore taskSepaphore = taskLock;
// This task will release the wrapper's lock.
Runnable task = new Runnable()
{
@Override
public void run()
{
try
{
if (isRunning && !wrapper.isEvicted())
invokeOperation(instance, Operation.output, null);
}
finally
{
wrapper.releaseLock();
// this signals that we're done.
synchronized(numExecutingOutputs)
{
numExecutingOutputs.decrementAndGet();
numExecutingOutputs.notifyAll();
}
if (taskSepaphore != null) taskSepaphore.release();
}
}
};
synchronized(numExecutingOutputs)
{
numExecutingOutputs.incrementAndGet();
}
if (executorService != null)
{
try
{
taskSepaphore.acquire();
executorService.execute(task);
}
catch (RejectedExecutionException e)
{
// this may happen because of a race condition between the
taskSepaphore.release();