I have two tasks: The first task (work) is reoccurring and the second task (cleanup) is releases some resources. The cleanup task should be run exactly once after the reoccurring work task has completed and will not be run again.
My first instinct was something like this:
ScheduledExecutorService service = ...;
ScheduledFuture<?> future = service.scheduleAtFixedRate(work, ...);
// other stuff happens
future.cancel(false);
cleanup.run();
The problem here is that cancel() returns immediately. So if work happens to be running, then cleanup will overlap it.
Ideally I would use something like Guava's Futures.addCallback(ListenableFuture future, FutureCallback callback). (Guava 15 may have something like that).
In the meantime, how can fire a callback when future is cancelled and work no longer running?
This is the solution that I've come up with. It seems to be pretty simple, but I still assume there's a more common and/or elegant solution out there. I'd really like to see one in a library like Guava...
First I create a wrapper to impose mutual exclusion on my Runnables:
private static final class SynchronizedRunnable implements Runnable {
private final Object monitor;
private final Runnable delegate;
private SynchronizedRunnable(Object monitor, Runnable delegate) {
this.monitor = monitor;
this.delegate = delegate;
}
#Override
public void run() {
synchronized (monitor) {
delegate.run();
}
}
}
Then I create a wrapper to fire my callback on successful invokations of cancel:
private static final class FutureWithCancelCallback<V> extends ForwardingFuture.SimpleForwardingFuture<V> {
private final Runnable callback;
private FutureWithCancelCallback(Future<V> delegate, Runnable callback) {
super(delegate);
this.callback = callback;
}
#Override
public boolean cancel(boolean mayInterruptIfRunning) {
boolean cancelled = super.cancel(mayInterruptIfRunning);
if (cancelled) {
callback.run();
}
return cancelled;
}
}
Then I roll it all together in my own method:
private Future<?> scheduleWithFixedDelayAndCallback(ScheduledExecutorService service, Runnable work, long initialDelay, long delay, TimeUnit unit, Runnable cleanup) {
Object monitor = new Object();
Runnable monitoredWork = new SynchronizedRunnable(monitor, work);
Runnable monitoredCleanup = new SynchronizedRunnable(monitor, cleanup);
Future<?> rawFuture = service.scheduleAtFixedRate(monitoredWork, initialDelay, delay, unit);
Future<?> wrappedFuture = new FutureWithCancelCallback(rawFuture, monitoredCleanup);
return wrappedFuture;
}
I'll give it another shot then. Either you may enhance the command or you may wrap the executed Runnable/Callable. Look at this:
public static class RunnableWrapper implements Runnable {
private final Runnable original;
private final Lock lock = new ReentrantLock();
public RunnableWrapper(Runnable original) {
this.original = original;
}
public void run() {
lock.lock();
try {
this.original.run();
} finally {
lock.unlock();
}
}
public void awaitTermination() {
lock.lock();
try {
} finally {
lock.unlock();
}
}
}
So you can change your code to
ScheduledExecutorService service = ...;
RunnableWrapper wrapper = new RunnableWrapper(work);
ScheduledFuture<?> future = service.scheduleAtFixedRate(wrapper, ...);
// other stuff happens
future.cancel(false);
wrapper.awaitTermination();
cleanup.run();
After calling cancel, either work is no longer running and awaitTermination() returns immediately, or it is running and awaitTermination() blocks until it's done.
Why don't you do
// other stuff happens
future.cancel(false);
service.shutdown();
service.awaitTermination(1, TimeUnit.DAYS);
cleanup.run();
This will tell your executor service to shutdown, thus allowing you to wait for the possibly running work to be finished.
Related
Problem:
I have a requirement to call a dao method at fix rate say every 10 sec, then I need to check if the result is valid if yes exit, else keep on calling that method every 10 sec till I get a valid result or defined time out (say 2 min) is over.
Approaches:
I want to keep the task and scheduler logic separate, and write a task in such a way that it can be used by different classes having similar requirement.
One way I can think is to define a new poller task
public abstract class PollerTask<T> implements Runnable {
abstract public boolean isValid(T result);
abstract public T task();
private T result;
private volatile boolean complete;
public boolean isComplete() {
return complete;
}
public T getResult() {
return result;
}
#Override
final public void run() {
result = task();
if (complete = isValid(result)) {
//may be stop scheduler ??
}
}
}
User need to simply provide implementation of task and isValid;
Then we can define a separate class that takes pooling freq and timeout and creates a scheduled executor and submit this task
public class PollerTaskExecutor {
private int pollingFreq;
private int timeout;
private ScheduledExecutorService executor;
private ScheduledExecutorService terminator;
private ExecutorService condition;
private volatile boolean done;
private ScheduledFuture future;
public PollerTaskExecutor(int pollingFreq, int timeout) {
this.pollingFreq = pollingFreq;
this.timeout = timeout;
executor = Executors.newSingleThreadScheduledExecutor();
terminator = Executors.newSingleThreadScheduledExecutor();
condition = Executors.newSingleThreadExecutor();
}
public void submitTaskForPolling(final PollerTask pollerTask) {
future = executor.scheduleAtFixedRate(pollerTask, 0, pollingFreq, TimeUnit.SECONDS);
terminator.schedule(new Runnable() {
#Override
public void run() {
complete();
}
}, timeout, TimeUnit.SECONDS);
condition.execute(new Runnable() {
#Override
public void run() {
if (pollerTask.isComplete()) {
complete();
}
}
});
}
public boolean isDone() {
return done;
}
public void complete() {
future.cancel(false);
executor.shutdown();
terminator.shutdown();
condition.shutdown();
done = true;
}
now user can wait till pollerExecutor.isDone returns true and get the result.
I had to use three executors for following purposes:
executor to run task at fix interval
executor to stop all when time out is over
executor to stop all if valid result is obtained before time out.
Can someone please suggest a better approach, this seems to be complicated for such a trivial task ?
Make it a self-scheduling task. In pseudo code:
public class PollingTaskRunner {
...
CountDownLatch doneWait = new CountDownLatch(1);
volatile boolean done;
PollingTaskRunner(Runnable pollingTask, int frequency, int period) {
...
endTime = now + period;
executor.schedule(this, 0);
}
run() {
try {
pollingTask.run();
} catch (Exception e) {
...
}
if (pollingTask.isComplete() || now + frequency > endTime) {
done = true;
doneWait.countDown();
executor.shutdown();
} else {
executor.schedule(this, frequency);
}
}
await() {
doneWait.await();
}
isDone() {
return done;
}
}
It is not that complicated but add plenty of debug statements the first time you run/test this so you know what is going on. Once it is running as intended, it is easy to re-use the pattern.
A slightly simpler method, you don't need a separate executor service for the terminator, you could simply push the terminator task into the same executor.
Even simpler. Have PollerTask place it's result in a BlockingQueue. Then have the PollingTaskRunner do a timed poll on that BlockingQueue. Whenever control is returned from the poll call ScheduledFuture.cancel because the task either succeeded or timed out.
How to set the Thread priority of a Timer in java? This is the code I have found in the project that I am working on, and I do not think that it is working:
public static Timer createNamedTimer(boolean isDaemon,
final String threadName, final int priority) {
Timer timer = new Timer(isDaemon);
timer.schedule(new TimerTask() {
public void run() {
Thread.currentThread().setName("TimerThread: " + threadName);
Thread.currentThread().setPriority(priority);
}
}, 0);
return timer;
}
AFAIK for timer the only way you can change priority is the way you are doing it.
If you need a better option you can use the ThreadFactory for creating the threads and setting their priority.
class SimpleThreadFactory implements ThreadFactory {
private int threadPriority;
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setPriority(threadPriority);
return t;
}
}
Then you can pass the factory to the Executors framework of Java for doing what you want, IMHO this will be a much better approach.
Why do I say it would be a better approach?
The Timer class's JavaDoc mentions ScheduledThreadPoolExecutor and notes, that this class is effectively a more versatile replacement for the Timer/TimerTask combination
The suggested solution won't likely work for tasks that are repeated more than once, because between invocations another task that shared the same thread may have adjusted the priority to something else. Therefore, for repeating tasks you must set the priority at execution time, every time. This potential issue exists w/or w/o the new Executors framework.
One solution is to create a wrapper class that does prep work for you to ensure consistency. For example:
AnyClass.java:
private static void exampleUsage()
{
try { launchHighPriorityTask(() -> System.out.println("What a fancy task.")).join(); }
catch (Throwable ignored) {}
}
private static Thread launchMaxPriorityTask(Runnable task)
{
final Thread customThread = new Thread(new Task("MaxPriority", Thread.MAX_PRIORITY, task));
customThread.start();
return customThread;
}
Task.java:
public class Task implements Runnable
{
private final String name;
private final int priority;
private final Runnable task;
public Task(String name, int priority, Runnable task)
{
if (null == task) throw new NullPointerException("no task provided");
this.name = name; this.priority = priority; this.task = task;
}
/**
* run() is made final here to prevent any deriving classes
* accidentally ruining the expected behavior
*/
#Override public final void run()
{
final Thread thread = Thread.currentThread();
// cache the current state to restore settings and be polite
final String prevName = thread.getName();
final int prevPriority = thread.getPriority();
// set our thread's config
thread.setName(name);
thread.setPriority(priority);
try { task.run(); } catch (Throwable ignored) {}
// restore previous thread config
thread.setPriority(prevPriority);
thread.setName(prevName);
}
}
This is naturally a minimalist example of what can be accomplished with this sort of setup.
Basically, I have a long task that consists of bunch of sequence sub-tasks as follows:
class Task implements Runnable
{
private Foo foo;
public Task(Foo foo)
{
this.foo = foo;
}
#Override
public void run()
{
doTask1(foo);
doTask2(foo);
doTask3(foo);
doTask4(foo);
// ...
doTaskN(foo);
}
}
What I need is to run only one instance of the Task, and if one Task begins, the other Tasks (if any) should terminate immediately.
I used a single thread executor:
Executor executor = Executors.newSingleThreadExecutor();
and I run the task as:
executor.execute(new Task(foo));
This guarantees that only one task executes at a time, but unfortunately it does not terminate the previous tasks.
However, I decide to use a boolean flag in between each 2 sub-tasks as follows:
class BooleanHolder
{
boolean terminate = false;
}
class Task implements Runnable
{
private Foo foo;
private BooleanHolder bh;
public Task(Foo foo, BooleanHolder bh)
{
this.foo = foo;
this.bh = bh;
}
#Override
public void run()
{
bh.terminate = false;
doTask1(foo);
if(bh.terminate) return;
doTask2(foo);
if(bh.terminate) return;
doTask3(foo);
if(bh.terminate) return;
doTask4(foo);
// ...
if(bh.terminate) return;
doTaskN(foo);
}
}
and use it like this:
BooleanHolder bh = new BooleanHolder();
// ...
bh.terminate = true;
executor.execute(new Task(foo, bh));
However, this seems to be inefficient solution and not thread safe. Do you suggest a better solution?
You should use the ExecutorService interface, instead of Executor, like this:
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit(new Task(foo));
You can then interrupt the running task in order to execute another task through the cancel method:
future.cancel(true);
As #RPT said however, you should structure your tasks in such a way to respond to interrupts, otherwise the interrupt signal will not have any effect. If your task has no operation which throws an InterruptedException, you should manually check the interrupt flag from time to time (similar to what you already did):
#Override
public void run()
{
....
if (Thread.interrupted()) {
// Release resources and end task
}
....
}
By the way, this solves your problem, but does not actually terminate the thread inside ExecutorService.
What I am after is a compatible way to configure the use of a thread pool or not. Ideally the rest of the code should not be impacted at all. I could use a thread pool with 1 thread but that isn't quite what I want. Any ideas?
ExecutorService es = threads == 0 ? new CurrentThreadExecutor() : Executors.newThreadPoolExecutor(threads);
// es.execute / es.submit / new ExecutorCompletionService(es) etc
Java 8 style:
Executor e = Runnable::run;
You can use Guava's MoreExecutors.newDirectExecutorService(), or MoreExecutors.directExecutor() if you don't need an ExecutorService.
If including Guava is too heavy-weight, you can implement something almost as good:
public final class SameThreadExecutorService extends ThreadPoolExecutor {
private final CountDownLatch signal = new CountDownLatch(1);
private SameThreadExecutorService() {
super(1, 1, 0, TimeUnit.DAYS, new SynchronousQueue<Runnable>(),
new ThreadPoolExecutor.CallerRunsPolicy());
}
#Override public void shutdown() {
super.shutdown();
signal.countDown();
}
public static ExecutorService getInstance() {
return SingletonHolder.instance;
}
private static class SingletonHolder {
static ExecutorService instance = createInstance();
}
private static ExecutorService createInstance() {
final SameThreadExecutorService instance
= new SameThreadExecutorService();
// The executor has one worker thread. Give it a Runnable that waits
// until the executor service is shut down.
// All other submitted tasks will use the RejectedExecutionHandler
// which runs tasks using the caller's thread.
instance.submit(new Runnable() {
#Override public void run() {
boolean interrupted = false;
try {
while (true) {
try {
instance.signal.await();
break;
} catch (InterruptedException e) {
interrupted = true;
}
}
} finally {
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}});
return Executors.unconfigurableScheduledExecutorService(instance);
}
}
Here's a really simple Executor (not ExecutorService, mind you) implementation that only uses the current thread. Stealing this from "Java Concurrency in Practice" (essential reading).
public class CurrentThreadExecutor implements Executor {
public void execute(Runnable r) {
r.run();
}
}
ExecutorService is a more elaborate interface, but could be handled with the same approach.
I wrote an ExecutorService based on the AbstractExecutorService.
/**
* Executes all submitted tasks directly in the same thread as the caller.
*/
public class SameThreadExecutorService extends AbstractExecutorService {
//volatile because can be viewed by other threads
private volatile boolean terminated;
#Override
public void shutdown() {
terminated = true;
}
#Override
public boolean isShutdown() {
return terminated;
}
#Override
public boolean isTerminated() {
return terminated;
}
#Override
public boolean awaitTermination(long theTimeout, TimeUnit theUnit) throws InterruptedException {
shutdown(); // TODO ok to call shutdown? what if the client never called shutdown???
return terminated;
}
#Override
public List<Runnable> shutdownNow() {
return Collections.emptyList();
}
#Override
public void execute(Runnable theCommand) {
theCommand.run();
}
}
I had to use the same "CurrentThreadExecutorService" for testing purposes and, although all suggested solutions were nice (particularly the one mentioning the Guava way), I came up with something similar to what Peter Lawrey suggested here.
As mentioned by Axelle Ziegler here, unfortunately Peter's solution won't actually work because of the check introduced in ThreadPoolExecutor on the maximumPoolSize constructor parameter (i.e. maximumPoolSize can't be <=0).
In order to circumvent that, I did the following:
private static ExecutorService currentThreadExecutorService() {
CallerRunsPolicy callerRunsPolicy = new ThreadPoolExecutor.CallerRunsPolicy();
return new ThreadPoolExecutor(0, 1, 0L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), callerRunsPolicy) {
#Override
public void execute(Runnable command) {
callerRunsPolicy.rejectedExecution(command, this);
}
};
}
You can use the RejectedExecutionHandler to run the task in the current thread.
public static final ThreadPoolExecutor CURRENT_THREAD_EXECUTOR = new ThreadPoolExecutor(0, 0, 0, TimeUnit.DAYS, new SynchronousQueue<Runnable>(), new RejectedExecutionHandler() {
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
r.run();
}
});
You only need one of these ever.
So, I'm curious. How do you handle setting maximum execution time for threads? When running in a thread pool?
I have several techniques but, I'm never quite satisfied with them. So, I figure I'd ask the community how they go about it.
How about:
Submit your Callable to the ExecutorService and keep a handle to the returned Future.
ExecutorService executorService = ... // Create ExecutorService.
Callable<Result> callable = new MyCallable(); // Create work to be done.
Future<Result> fut = executorService.submit(callable);
Wrap the Future in an implementation of Delayed whereby Delayed's getDelay(TimeUnit) method returns the maximum execution time for the work in question.
public class DelayedImpl<T> implements Delayed {
private final long maxExecTimeMillis;
private final Future<T> future;
public DelayedImpl(long maxExecTimeMillis, Future<T> future) {
this.maxExecMillis = maxExecMillis;
this.future = future;
}
public TimeUnit getDelay(TimeUnit timeUnit) {
return timeUnit.convert(maxExecTimeMillis, TimeUnit.MILLISECONDS);
}
public Future<T> getFuture() {
return future;
}
}
DelayedImpl impl = new DelayedImpl(3000L, fut); // Max exec. time == 3000ms.
Add the `DelayedImpl` to a `DelayQueue`.
Queue<DelayedImpl> queue = new DelayQueue<DelayImpl>();
queue.add(impl);
Have a thread repeatedly take() from the queue and check whether each DelayedImpl's Future is complete by calling isDone(); If not then cancel the task.
new Thread(new Runnable() {
public void run() {
while (!Thread.interrupted) {
DelayedImpl impl = queue.take(); // Perform blocking take.
if (!impl.getFuture().isDone()) {
impl.getFuture().cancel(true);
}
}
}
}).start();
The main advantage to this approach is that you can set a different maximum execution time per task and the delay queue will automatically return the task with the smallest amount of execution time remaining.
Normally, I just poll regularly a control object from the threaded code. Something like:
interface ThreadControl {
boolean shouldContinue();
}
class Timer implements ThreadControl {
public boolean shouldContinue() {
// returns false if max_time has elapsed
}
}
class MyTask implements Runnable {
private tc;
public MyTask(ThreadControl tc) {
this.tc = tc;
}
public void run() {
while (true) {
// do stuff
if (!tc.shouldContinue())
break;
}
}
}
Adamski:
I believe that your implementation of the Delayed Interface requires some adjustment in order to work properly. The return value of 'getDelay()' should return a negative value if the amount of time elapsed from the instantiation of the object has exceeded the maximum lifetime. To achieve that, you need to store the time when the task was created (and presumably started). Then each time 'getDelay()' is invoked, calculate whether or not the maximum lifetime of the thread has been exceeded. As in:
class DelayedImpl<T> implements Delayed {
private Future<T> task;
private final long maxExecTimeMinutes = MAX_THREAD_LIFE_MINUTES;
private final long startInMillis = System.currentTimeMillis();
private DelayedImpl(Future<T> task) {
this.task = task;
}
public long getDelay(TimeUnit unit) {
return unit.convert((startInMillis + maxExecTimeMinutes*60*1000) - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
public int compareTo(Delayed o) {
Long thisDelay = getDelay(TimeUnit.MILLISECONDS);
Long thatDelay = o.getDelay(TimeUnit.MILLISECONDS);
return thisDelay.compareTo(thatDelay);
}
public Future<T> getTask() {
return task;
}
}