Steve Chambers Steve Chambers - 1 month ago 5
Java Question

Can 'this' be passed into ScheduledExecutorService.scheduleWithFixedDelay()?

I'm looking at using the

java.util.concurrent
package for a simple polling class. Am a bit perplexed by the range of classes, interfaces and methods available for doing this so would appreciate some guidance. Here are my thoughts so far:

The first decision to make is how to instantiate the class for managing a schedule. There are a few possible options, e.g:

ScheduledThreadPoolExecutor scheduledThreadPoolExecutor =
new ScheduledThreadPoolExecutor(corePoolSize)


...or...

ScheduledExecutorService scheduledExecutorService =
Executors.newSingleThreadScheduledExecutor();


...or...

ScheduledExecutorService scheduledExecutorService =
Executors.newScheduledThreadPool(corePoolSize);


Am leaning towards the last one but wondering what a sensible corePoolSize would be - perhaps 1 to keep things simple?

EDIT: In the end I found most benefit in using the top method (i.e. directly instantiate ScheduledThreadPoolExecutor). ThreadPoolExecutor provides
getActiveCount()
for obtaining the number of active threads. This allowed me to implement a
pause()
method that waits until the pause has actually taken effect - see discussion.


The next decision is whether to call
scheduleAtFixedRate
or
scheduleWithFixedDelay
. Am leaning towards
scheduleWithFixedDelay()
since the polling regularity isn't all that important and I don't like the idea of multiple polls occurring in quick succession after a bottleneck.

But here's the question: Would it be OK/advisable to use a single class that both starts the polling and represents the thread? E.g:

public class Poller extends Thread {
@Override
public void run() {
...
}

public void startPolling() {
ScheduledExecutorService exec = Executors.newScheduledThreadPool(1);
exec.scheduleWithFixedDelay(this, 0, 5000, TimeUnit.MILLISECONDS);
}
}


The main part I'm not sure about here is the first
scheduleWithFixedDelay()
parameter: Will a new instance of this class be instantiated for each execution? Otherwise it surely wouldn't work since run() can't be called on the same Thread instance twice?

Answer

As others have commented, all you need to change is Thread to Runnable. You might want to add some safe guard so that there is not multiple tasks being run.

public class Poller implements Runnable {
    final ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
    Future future = null;

    @Override
    public void run() {
        ...
    }

    public void startPolling() {
        if (future != null && !future.isDone()) {
           future.cancel(true); // stop before restarting
           // or
           return; // already running
        }
        future = exec.scheduleWithFixedDelay(this, 0, 5000, TimeUnit.MILLISECONDS);
    }
}

BTW: If you have Java 5.0, the run() method does not have the @Override. For Java 6+, you should have the @Override.

Will a new instance of this class be instantiated for each execution?

A new instances is created when you use the new operator.

Otherwise it surely wouldn't work run() surely can't be called on the same Thread instance twice?

It can work because the use of Thread in your code is confusing as the thread you create is not used. It just needs to be Runnable.