Search code examples
javaandroidmultithreadingrunnablejava-threads

ScheduledThreadPoolExecutor afterExecute's runnable.toString is different


I am relatively new to ThreadPoolExecutor. I'm seeing if I can track the runnable before being executed and in afterExecute.

By getting runnable.toString() using afterExecute(Runnable t, Throwable t). Now, I realize I could just put a Log inside the runnable itself... but I was curious what this method would produce.

For ThreadPoolExecutor, works fine, runnable.toString is the same before execute(runnable) and also in afterExecute().

However! ScheduledThreadPoolExecutor is different. Its afterExecute's runnable.toString is quite different.

For example, before: my.pkg.name@abc, afterExecute: java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask@zxc

Not even the pkg name is the same. Why is this?

private MyThreadPool() {
    threadPool = new ThreadPoolExecutor(NUMBER_OF_CORES, MAX_CORES,
        KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT, workQueue) {
        @Override
        public void afterExecute(Runnable r, Throwable t) {
            super.afterExecute(r, t);
            Log.d(TAG, "ThreadOps onDone: " + r.toString());
            // (A) will return same --> mypkgname@abc
        }
    };
    threadPool.setRejectedExecutionHandler(rejectedHandler);

    scheduledThreadPool = new ScheduledThreadPoolExecutor(NUMBER_OF_CORES) {
        @Override
        public void afterExecute(Runnable r, Throwable t) {
            super.afterExecute(r, t);
            Log.d(TAG, "ThreadOps onDelayDone: " + r.toString());
            // (D) does not return same?
            // I am expecting --> mypkgname@qwe , but get...
            // java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask@zxc
        }
    };
    scheduledThreadPool.setRejectedExecutionHandler(rejectedHandler);
}

public void execute(Runnable runnable) {
    Log.d(TAG, "ThreadOps exe: " + runnable.toString());
    // (A) lets say toString --> mypkgname@abc
    threadPool.execute(runnable);
}

public void delayExecute(Runnable runnable, long delayms) {
    Log.d(TAG, "ThreadOps exe @" + delayms + ": " + runnable.toString());
    // (D) lets say toString --> mypkgname@qwe
    scheduledThreadPool.schedule(runnable, delayms, TimeUnit.MILLISECONDS);
}

Solution

  • ScheduledThreadPoolExecutor internally maintains a heap of sorts to easily add and retrieve submitted tasks based on their scheduled (ie. the one that needs to be executed next at the top of the heap).

    To help accessing this heap, the implementation of ScheduledThreadPoolExecutor decorates the Runnable or Callable instances you schedule with a custom implementation that describes its position in the heap, among other things. That's the ScheduledFutureTask you see in your logs. Note that this is an implementation detail (it's a private class) and you shouldn't rely on it.