I have a method that will be called all the time.
After calling, a job(runnable) will be generated and submitted to the thread pool. The timeout time of each job is different, depending on the incoming parameters.
Now I want to monitor whether each job can end within the timeout time when it starts to execute. What should I do?
Note that timeout is from the beginning of execution to the end of execution, not from the time of delivery to the thread pool to the end of task execution. Because of this, I don't think future #get (timeout) can be used, am I right?.
And acceptJob should not block, it has to return immediately after submitting the job(maybe some other logic, but not block).
ExecutorService pool = Executors.newFixedThreadPool(10);
public void acceptNewJob(Map<String, Object> params) {
// timeout from params
int timeoutInMs = (int) params.get("timeoutInMs");
pool.submit(new Runnable() {
#Override
public void run() {
// generate a job by params
// if this job execute timeout, need alarm
}
});
}
How about wrapping every runnable and use a Timer to check the runnable's status when the timeout period expires.
public void acceptNewJob(Map<String, Object> params) {
// timeout from params
int timeoutInMs = (int) params.get("timeoutInMs");
MonitoredRunnable runnable = new MonitoredRunnable(new Runnable() {
#Override
public void run() {
// generate a job by params
// if this job execute timeout, need alarm
}
}, timeoutInMs);
pool.submit(runnable);
}
// Or use ScheduledThreadPoolExecutor
private Timer timer = new Timer();
public class MonitoredRunnable implements Runnable {
private volatile int state = READY;
public static final int READY = 0;
public static final int RUNNING = 1;
public static final int COMPLETE = 0;
private Runnable task;
private int timeoutInMs;
public MonitoredRunnable(Runnable task, int timeoutInMs) {
this.task = task;
this.timeoutInMs = timeoutInMs;
}
#Override
public void run() {
state = RUNNING;
startMonitor(this);
task.run();
state = COMPLETE;
}
private void startMonitor(MonitoredRunnable runnable) {
timer.schedule(new TimerTask() {
#Override
public void run() {
try {
if (runnable.state != COMPLETE) {
System.out.println("Job timeout.");
// alarm
}
} catch (Exception e) {
//
}
}
}, runnable.timeoutInMs);
}
Related
I know there are many frameworks for Scheduler as well as JDK's own Scheduler. I can't use any third party framework/API. The existing scheduler uses only Java API. It is as follows:-
public class Timer implements Runnable {
private Thread runner;
private int pause;
private Task task;
private boolean running;
public Timer(int pause, Task task) {
this.pause = pause;
this.task = task;
runner = new Thread(this, "Timer");
}
public void run() {
try {
while (running) {
task.run(); // long running task
synchronized (runner) {
runner.wait(pause);
}
}
} catch (InterruptedException ie) {
/* The user probably stopped the */
}
}
Interface and class:-
public interface Task {
void run();
}
public class TaskManager implements Task {
private static boolean firstRun = true;
private static Timer timer;
private static String lastRun;
public static void start(int interval) {
// stop any previous
if (timer != null) {
timer.stopTimer();
timer = null;
}
// Start a new one
TaskManager taskManager = new TaskManager ();
timer = new Timer(interval * 1000, taskManager );
timer.startTimer();
}
public void run() {
// long running code
}
public void setDelay(int p) {
pause = p;
}
public void startTimer() {
running = true;
runner.start();
}
public void stopTimer() {
running = false;
runner.interrupt();
}
}
From a servelet I call as:
private void startTaskManager() {
TaskManager.start(30);
}
My requirements that it will perform task in a thread in the run() method. There are many tasks that will be picked one after another from the database.
The above implementation has some issues. On the above implementation, it has own interface Task and implemented own Timer.
I think there is another better way to achieve this scheduler. Please suggest me.
When any command scheduled with fixed rate at any ScheduledExecutorService, it returns ScheduledFuture which can be cancelled as well.
But "cancel" does not provide guarantee that command is not still executing after cancel returns, for example because command was already in the middle of execution when "cancell" was called.
For mostly use cases it is enough functionality. But I have deal with usecase when need to block current thread after cancel, if command already is in progress, and wait until command done. In other words thread which called cancel should not go forward if command still executing. Cancelling with mayInterruptIfRunning=true also is not suitable, because I do not want to broke current executions, I just need to wait for normal complete.
I did not found how to achieve this requirements via standard JDK classes. Question1: Was I wrong and this kind of functionality exists?
So I decided to implement it by itself:
import java.util.concurrent.*;
public class GracefullyStoppingScheduledFutureDecorator implements ScheduledFuture {
/**
* #return the scheduled future with method special implementation of "cancel" method,
* which in additional to standard implementation,
* provides strongly guarantee that command is not in the middle of progress when "cancel" returns
*/
public static ScheduledFuture schedule(Runnable command, long initialDelay, long period, TimeUnit unit, ScheduledExecutorService scheduler) {
CancellableCommand cancellableCommand = new CancellableCommand(command);
ScheduledFuture future = scheduler.scheduleAtFixedRate(cancellableCommand, initialDelay, period, unit);
return new GracefullyStoppingScheduledFutureDecorator(future, cancellableCommand);
}
private GracefullyStoppingScheduledFutureDecorator(ScheduledFuture targetFuture, CancellableCommand command) {
this.targetFuture = targetFuture;
this.runnable = command;
}
private final ScheduledFuture targetFuture;
private final CancellableCommand runnable;
#Override
public boolean cancel(boolean mayInterruptIfRunning) {
runnable.cancel();
return targetFuture.cancel(mayInterruptIfRunning);
}
#Override
public long getDelay(TimeUnit unit) {
return targetFuture.getDelay(unit);
}
#Override
public int compareTo(Delayed o) {
return targetFuture.compareTo(o);
}
#Override
public boolean isCancelled() {
return targetFuture.isCancelled();
}
#Override
public boolean isDone() {
return targetFuture.isDone();
}
#Override
public Object get() throws InterruptedException, ExecutionException {
return targetFuture.get();
}
#Override
public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return targetFuture.get(timeout, unit);
}
private static class CancellableCommand implements Runnable {
private final Object monitor = new Object();
private final Runnable target;
private boolean cancelled = false;
private CancellableCommand(Runnable target) {
this.target = target;
}
public void cancel() {
synchronized (monitor) {
cancelled = true;
}
}
#Override
public void run() {
synchronized (monitor) {
if (!cancelled) {
target.run();
}
}
}
}
}
Question2: Could anybody find errors in the code above?
Question2: Could anybody find errors in the code above?
There is hypothetical deadlock which can be reproduced by following scenario:
Having thread T1 which holds monitor M1
Scheduled task is executing(holds its monitor M2) on thread T2 and wants to enter to M1, so T2 need to wait until T1 exits monitor M1.
T1 decided to cancel task, but because its monitor M2 is locked by task itself we have the deadlock.
Most likely scenario abovr is unreal, but to protect from all possible cases, I decided to rewrite code in lock-free manner:
public class GracefullyStoppingScheduledFuture {
/**
* #return the scheduled future with method special implementation of "cancel" method,
* which in additional to standard implementation,
* provides strongly guarantee that command is not in the middle of progress when "cancel" returns
*/
public static GracefullyStoppingScheduledFuture cheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit, ScheduledExecutorService scheduler) {
CancellableCommand cancellableCommand = new CancellableCommand(command);
ScheduledFuture future = scheduler.scheduleAtFixedRate(cancellableCommand, initialDelay, period, unit);
return new GracefullyStoppingScheduledFuture(future, cancellableCommand);
}
private GracefullyStoppingScheduledFuture(ScheduledFuture targetFuture, CancellableCommand command) {
this.targetFuture = targetFuture;
this.runnable = command;
}
private final ScheduledFuture targetFuture;
private final CancellableCommand runnable;
public void cancelAndBeSureOfTermination(boolean mayInterruptIfRunning) throws InterruptedException, ExecutionException {
try {
targetFuture.cancel(mayInterruptIfRunning);
} finally {
runnable.cancel();
}
}
private static class CancellableCommand implements Runnable {
private static final int NOT_EXECUTING = 0;
private static final int IN_PROGRESS = 1;
private static final int CANCELLED_WITHOUT_OBSTRUCTION = 2;
private static final int CANCELLED_IN_MIDDLE_OF_PROGRESS = 3;
private final AtomicInteger state = new AtomicInteger(NOT_EXECUTING);
private final AtomicReference<Thread> executionThread = new AtomicReference<>();
private final CompletableFuture<Void> cancellationFuture = new CompletableFuture<>();
private final Runnable target;
private CancellableCommand(Runnable target) {
this.target = target;
}
public void cancel() throws ExecutionException, InterruptedException {
if (executionThread.get() == Thread.currentThread()) {
// cancel method was called from target by itself
state.set(CANCELLED_IN_MIDDLE_OF_PROGRESS);
return;
}
while (true) {
if (state.get() == CANCELLED_WITHOUT_OBSTRUCTION) {
return;
}
if (state.get() == CANCELLED_IN_MIDDLE_OF_PROGRESS) {
cancellationFuture.get();
return;
}
if (state.compareAndSet(NOT_EXECUTING, CANCELLED_WITHOUT_OBSTRUCTION)) {
return;
}
if (state.compareAndSet(IN_PROGRESS, CANCELLED_IN_MIDDLE_OF_PROGRESS)) {
cancellationFuture.get();
return;
}
}
}
#Override
public void run() {
if (!state.compareAndSet(NOT_EXECUTING, IN_PROGRESS)) {
notifyWaiters();
return;
}
try {
executionThread.set(Thread.currentThread());
target.run();
} finally {
executionThread.set(null);
if (!state.compareAndSet(IN_PROGRESS, NOT_EXECUTING)) {
notifyWaiters();
}
}
}
private void notifyWaiters() {
if (state.get() == CANCELLED_WITHOUT_OBSTRUCTION) {
// no need to notify anything
return;
}
// someone waits for cancelling
cancellationFuture.complete(null);
return;
}
}
I want to limit the number of calls for a method to 5 within 10 seconds. There will be calls to the method from different threads. After that time has passed, I want the counter for the method to be resetted so for the next 10 seconds, 5 more calls can be made and this will go on. What could be a good way to do this?
Thanks
Maybe use a Semaphore and a Timer to release tokens:
public class RateLimitedTask() {
private final Timer timer = new Timer();
private final Semaphore semaphore;
private final Runnable task;
public RateLimitedTask(
final Runnable task,
final int limit,
final int delay
) {
this.task = task;
semaphore = new Semaphore(limit);
timer.schedule(new TimerTask() {
#Override
public void run() {
semaphore.release(limit);
}
}, delay*1000, delay*1000);
}
public void run() throws InterruptedException {
semaphore.acquire();
task.run();
}
}
In a web server i wrote, each request invokes a list of actions. Some of these actions aren't as critical as others, so I would like to run them in a background thread.
Also, since they aren't that important I don't care if one of them fails seldomly, and I don't want them to take up a thread forever, so other threads would be available to process the next batch.
So, I would like to have a thread pool (e.g.: 10 threads) and hand out a thread to each background task like this. Limit each thread to 1 second, and if it doesn't finish by that time, just kill it, and be available for the next task to come in.
How would I go about doing this ?
So far, this is what I have :
public class AsyncCodeRunner {
private static final ExecutorService executor = Executors.newFixedThreadPool(10);
public void Run(Callable<Void> callableCode, int timeout) {
final int threadTimeout = 10;
Future<Void> callableFuture = executor.submit(callableCode);
try {
callableFuture.get(threadTimeout, TimeUnit.SECONDS);
} catch (Exception e) {
logger.Info("Thread was timed out", e);
}
}
}
And I want to use this class like this :
public void processRequest(RequestObject request) {
// do some important processing
// throw some less important processing to background thread
(new AsyncCodeRunner()).Run(new Callable<Void> () {
#Override
public Void call() throws Exception {
// do something...
return null;
}
}, 1); // 1 second timeout
// return result (without waiting for background task)
return;
}
Will this work like I want it to ? Or how should I change it so it would ?
And what happens if I call Run() but there are no available threads in the threadpool to hand out ?
I think your primary problem with this rather elegant idea is that you are only timing out on the get of the Future, you are not actually aborting the process once it times out, you are just giving up waiting for it. The issue becomes even more complex when you realise that you may even time out when the process hasn't even started - it is just still in the queue.
Perhaps something like this would be effective. It does require two threads but a TimerTask thread should consume very little.
public class RunWithTimeout {
public RunWithTimeout(Runnable r, long timeout) {
// Prepare the thread.
final Thread t = new Thread(r);
// Start the timer.
new Timer(true).schedule(new TimerTask() {
#Override
public void run() {
if (t.isAlive()) {
// Abort the thread.
t.interrupt();
}
}
}, timeout * 1000);
// Start the thread.
t.start();
}
}
class WaitAFewSeconds implements Runnable {
final long seconds;
WaitAFewSeconds(long seconds) {
this.seconds = seconds;
}
#Override
public void run() {
try {
Thread.sleep(seconds * 1000);
} catch (InterruptedException ie) {
System.out.println("WaitAFewSeconds(" + seconds + ") - Interrupted!");
}
}
}
public void test() {
new RunWithTimeout(new WaitAFewSeconds(5), 3);
new RunWithTimeout(new WaitAFewSeconds(3), 5);
}
Here's an alternative that only uses one extra thread.
public class ThreadKiller implements Runnable {
DelayQueue<WaitForDeath> kill = new DelayQueue<>();
private class WaitForDeath implements Delayed {
final Thread t;
final long finish;
public WaitForDeath(Thread t, long wait) {
this.t = t;
this.finish = System.currentTimeMillis() + wait;
}
#Override
public long getDelay(TimeUnit unit) {
return unit.convert(finish - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
#Override
public int compareTo(Delayed o) {
long itsFinish = ((WaitForDeath) o).finish;
return finish < itsFinish ? -1 : finish == itsFinish ? 0 : 1;
}
}
#Override
public void run() {
while (true) {
try {
WaitForDeath t = kill.take();
if (t.t.isAlive()) {
// Interrupt it.
t.t.interrupt();
}
} catch (InterruptedException ex) {
// Not sure what to do here.
}
}
}
public void registerThread(Thread t, long wait) {
// Post it into the delay queue.
kill.add(new WaitForDeath(t, wait));
}
}
public void test() throws InterruptedException {
// Testing the ThreadKiller.
ThreadKiller killer = new ThreadKiller();
Thread killerThread = new Thread(killer);
killerThread.setDaemon(true);
Thread twoSeconds = new Thread(new WaitAFewSeconds(2));
Thread fourSeconds = new Thread(new WaitAFewSeconds(4));
killer.registerThread(twoSeconds, 5000);
killer.registerThread(fourSeconds, 3000);
killerThread.start();
twoSeconds.start();
fourSeconds.start();
System.out.println("Waiting");
Thread.sleep(10 * 1000);
System.out.println("Finished");
killerThread.interrupt();
}
You need to start timer when the thread runs. Then no thread in waiting state will be killed. Here is the sample from this thread:
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class PoolTest {
class TimeOutTask extends TimerTask {
Thread t;
TimeOutTask(Thread t) {
this.t = t;
}
public void run() {
if (t != null && t.isAlive()) {
t.interrupt();
}
}
}
class MyRunnable implements Runnable {
Timer timer = new Timer(true);
public void run() {
timer.schedule(new TimeOutTask(Thread.currentThread()), 1000);
try {
System.out.println("MyRunnable...");
Thread.sleep(10000);
} catch (InterruptedException ie) {
System.out.println("MyRunnable error...");
ie.printStackTrace();
}
}
}
public static void main(String args[]) {
new PoolTest();
}
public PoolTest() {
try {
ExecutorService pe = Executors.newFixedThreadPool(3);
pe.execute(new MyRunnable());
} catch (Exception e) {
e.printStackTrace();
}
}
}
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.