Fields Summary |
---|
private volatile Throwable | mThrowablea Throwable if anything was thrown from the run loop |
private volatile CountDownLatch | mLatchmeans to block client threads until done |
private final String | mNameoptional name of the task |
private volatile boolean | mUseRandomSleepdebugging: whether to sleep a random amount. See {@link #setUseRandomSleep} |
private final T | mData |
private volatile long | mSubmitNanos |
private volatile long | mRunStartNanos |
private volatile long | mRunDoneNanos |
private final com.sun.appserv.management.helper.AMXDebugHelper | mDebug |
private static final AtomicInteger | mThreadsRunning |
private static final ExecutorService | _DefaultExecutorService |
private static final long | MAX_RANDOM_SLEEP_MILLIS |
private static final com.sun.appserv.management.util.misc.Timings | TIMINGS |
Methods Summary |
---|
private void | _submit(com.sun.appserv.management.util.misc.RunnableBase$HowToRun howToRun)
if ( howToRun != HowToRun.RUN_IN_CURRENT_THREAD && howToRun != HowToRun.RUN_IN_SEPARATE_THREAD )
{
throw new IllegalArgumentException();
}
if ( mLatch != null )
{
// already in progress
throw new IllegalStateException();
}
mSubmitNanos = System.nanoTime();
if ( howToRun == HowToRun.RUN_IN_CURRENT_THREAD )
{
runSync();
}
else
{
mLatch = new CountDownLatch(1);
runInSeparateThread( this );
}
|
private static java.util.concurrent.ExecutorService | createExecutorService()
// Testing at startup shows that a thread pool equal in size to the number
// of processors offers the best performance. However, this can 'hang'
// services that expect their threads to run once submitted.
return Executors.newCachedThreadPool();
|
private void | debug(java.lang.Object args)
if ( mDebug.getDebug() )
{
mDebug.println( args );
}
|
protected abstract void | doRun()
|
public final T | getData() return mData;
|
public static java.util.concurrent.ExecutorService | getDefaultExecutorService()
return _DefaultExecutorService;
|
protected java.util.concurrent.ExecutorService | getExecutorService()Subclasses may override the choice of ExecutorService
return getDefaultExecutorService();
|
public java.lang.String | getName()
return (mName == null || mName.length() == 0) ? this.getClass().getName() : mName;
|
public long | getNanosFromRunStart()
return mRunDoneNanos - mRunStartNanos;
|
public long | getNanosFromSubmit()
return mRunDoneNanos - mSubmitNanos;
|
public com.sun.appserv.management.util.misc.RunnableBase$HowToRun | getRecommendedSubmitType()Taking into account single vs multi-core, the number of RunnableBase currently
running, return a recommended HowToRun.
Callers that know significant I/O is involved should usually submit using
HowToRun.RUN_IN_SEPARATE_THREAD, even on single processor machines.
Callers with long-running tasks should generally not call this method; it's best used
with numbers of short-running tasks.
A subclass that knows it performs I/O might override this method to usually or always
return HowToRun.RUN_IN_SEPARATE_THREAD.
final int numProcessors = Runtime.getRuntime().availableProcessors();
final boolean singleCore = numProcessors == 1;
HowToRun howToRun = HowToRun.RUN_IN_CURRENT_THREAD;
if ( singleCore )
{
// try to keep it to just one thread; there could be some I/O
howToRun = mThreadsRunning.intValue() <= 1 ?
HowToRun.RUN_IN_SEPARATE_THREAD : HowToRun.RUN_IN_CURRENT_THREAD;
}
else
{
final int CUTOFF = numProcessors * 2;
if ( mThreadsRunning.intValue() <= CUTOFF )
{
howToRun = HowToRun.RUN_IN_SEPARATE_THREAD;
}
else
{
// all cores are busy (though this might be stale as soon as we checked).
howToRun = HowToRun.RUN_IN_CURRENT_THREAD;
}
}
return howToRun;
|
public long | getRunLatency()
return mRunStartNanos - mSubmitNanos;
|
public static com.sun.appserv.management.util.misc.Timings | getTimings()
return TIMINGS;
|
protected java.lang.Throwable | launderThrowable(java.lang.Throwable t)A subclass may transform the thrown exception (if any) into a more appropriate or
expected kind.
return t;
|
public final void | run()May be called synchronously or via another thread {@link #submit}.
See {@link #waitDone} and {@link #waitDoneThrow} and {@link #getThrowable}.
final int numRunning = mThreadsRunning.incrementAndGet();
// debug("Submitted ", getName(), ", #of threads = ", numRunning );
try {
runSync();
}
finally {
mThreadsRunning.decrementAndGet();
}
|
protected void | runInSeparateThread(java.lang.Runnable r)Run in a separate thread. Calls getExecutorService().submit(r).
Subclasses may override if desired.
getExecutorService().submit( r );
|
private final void | runSync()
mRunStartNanos = System.nanoTime();
if ( mUseRandomSleep )
{
final long sleepMillis = (System.currentTimeMillis() >> 4) % MAX_RANDOM_SLEEP_MILLIS;
debug( "Random sleep for: " + sleepMillis + "ms" );
sleepMillis( sleepMillis );
}
try
{
doRun();
}
catch( Throwable t )
{
mThrowable = t;
}
finally
{
mRunDoneNanos = System.nanoTime();
//debug( toString() );
if ( mLatch != null ) // could be null if RUN_IN_CURRENT_THREAD
{
mLatch.countDown();
mLatch = null; // it only counts down to 1, so forget about it
}
// do this after we release the latch
final String msg = "RunnableBase-" + StringUtil.quote(getName());
final long runTime = getNanosFromSubmit();
getTimings().add( msg, runTime);
//debug( "TIME TO ADD TIMING: " + (System.nanoTime() - start ) );
}
|
public void | setUseRandomSleep(boolean useRandom)Good for debugging timing issues; a task will insert an artificial delay
by a random amount.
mUseRandomSleep = useRandom;
|
protected static void | sleepMillis(long millis)
try
{
Thread.sleep( millis );
}
catch( InterruptedException e )
{
}
|
public void | submit()Calls submit( RUN_IN_SEPARATE_THREAD ).
_submit( getRecommendedSubmitType() );
|
public void | submit(com.sun.appserv.management.util.misc.RunnableBase$HowToRun howToRun)Submit the task for execution with {@link #submit()}. If 'waitTillDone'
is true, then this method won't return until the task has finished. This
method is useful as a transition method in the course of converting from
serialized execution to threaded execution, allowing a simple boolean switch
to make the change in behavior.
The task is still executed in its own thread, so as to produce the same
runtime environment that would be used for asynchronous execution (eg thread-local
variables).
_submit( howToRun );
|
public java.lang.String | toString()
final String delim = ", ";
final boolean started = mSubmitNanos != 0;
final boolean done = mRunDoneNanos != 0;
final long runTimeNanos = started ?
(done ? (mRunDoneNanos - mRunStartNanos) : System.nanoTime() - mRunStartNanos) : 0;
final String throwable = mThrowable == null ? "" : mThrowable.toString();
final String runTimeString = StringUtil.getTimingString( runTimeNanos );
return "Runnable \"" + this.getClass().getName() + "\"" + delim + "name = " + getName() +
delim + "started=" + started + delim + "done=" + done +
delim + "run-time=" + runTimeString + delim + throwable;
|
public final java.lang.Throwable | waitDone()Block until the task has finished, and return any Throwable (hopefully null).
// if mLatch is null, it was run synchronously, or has already finished (or never started)
// use temp, avoid race condition between null check and usage should mLatch go null
// after check for null
final CountDownLatch latch = mLatch;
if ( latch != null )
{
try
{
latch.await();
}
catch( final InterruptedException intr )
{
throw new RuntimeException( intr );
}
}
return mThrowable;
|
public final void | waitDoneThrow()Block until the task has finished. If a Throwable was thrown, then this method
will rethrow it, or a RuntimeException.
final Throwable t = waitDone();
if ( t != null )
{
if ( t instanceof RuntimeException )
{
throw (RuntimeException)t;
}
else if ( t instanceof Error )
{
throw (Error)t;
}
else
{
throw new RuntimeException( t );
}
}
|