// 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();
wrapper.releaseLock(); // we never got into the run so we need to release the lock
}
catch (InterruptedException e)
{
// this can happen while blocked in the semaphore.acquire.
// if we're no longer running we should just get out
// of here.
//
// Not releasing the taskSepaphore assumes the acquire never executed.
// if (since) the acquire never executed we also need to release the
// wrapper lock or that Mp will never be usable again.
wrapper.releaseLock(); // we never got into the run so we need to release the lock
}
}
else
task.run();
iter.remove();
} // end if we got the lock
} // end loop over every Mp
} // end while there are still Mps that haven't had output invoked.
// =======================================================
// now make sure all of the running tasks have completed
synchronized(numExecutingOutputs)
{
while (numExecutingOutputs.get() > 0)
{
try { numExecutingOutputs.wait(); }
catch (InterruptedException e)
{
// if we were interupted for a shutdown then just stop
// waiting for all of the threads to finish
if (!isRunning)