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.
Related
I have a class that starts multiple threads which all run while(true) loops. Is it possible to have an Assert statements on the state of a test after it has run for a certain amount of time?
The Timeout functionality would work, if it didn't fail the test.
This is a contrived example to show what I'm trying to do. The test is at the bottom.
class RunProgram {
private DataClass dataClass = new DataClass();
private Thread1 thread1 = new Thread1(dataClass);
void startThis() {
ExecutorService pool = Executors.newFixedThreadPool(5);
try {
pool.execute(thread1);//Thread 1
//... more threads with while loops
runMainThread(dataClass);
} finally {
pool.shutdown();
}
}
void runMainThread(DataClass data1){
while(true){
dataClass.setInternalDataInt(20);
//do stuff
}
}
public Thread1 getThread1(){
return this.thread1;
}
}
class Thread1 implements Runnable{
private DataClass dataClass;
Thread1(DataClass dataClass){
this.dataClass = dataClass;
}
public void run() {
dataClass.setInternalDataInt(10);
while (true) {
//dostuff
}
}
public DataClass getDataClass(){
return dataClass;
}
public void setDataClass(DataClass dataClass){
this.dataClass = dataClass;
}
}
class DataClass {
private int internalDataInt;
public int getInternalDataInt(){
return this.internalDataInt;
}
public void setInternalDataInt(int internalDataInt){
this.internalDataInt = internalDataInt;
}
}
class Tests{
#Test
public void stateOfThread1() {
RunProgram runProgram = new RunProgram();
runProgram.startThis();
//Run above for 100 millisecond and then end
Assertions.assertEquals(runProgram.getThread1().getDataClass().getInternalDataInt(), 20);
}
}
Found what I was looking for.
Use a ScheduledExecutorService:
An ExecutorService that can schedule commands to run after a given
delay, or to execute periodically.
RunProgram runProgram = new RunProgram();
ScheduledExecutorService testExecutor = Executors.newScheduledThreadPool(1);
Future future = testExecutor.submit(runProgram);
Thread.sleep(500);
future.cancel(true);
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);
}
As Brian Goetz states: "TrackingExecutor has an unavoidable race condition that could make it yield false positives: tasks that are identified as cancelled but actually completed. This arises because the thread pool could be shut down between when the last instruction of the task executes and when the pool records the task as complete."
TrackingExecutor:
/**
* TrackingExecutor
* <p/>
* ExecutorService that keeps track of cancelled tasks after shutdown
*
* #author Brian Goetz and Tim Peierls
*/
public class TrackingExecutor extends AbstractExecutorService {
private final ExecutorService exec;
private final Set<Runnable> tasksCancelledAtShutdown =
Collections.synchronizedSet(new HashSet<Runnable>());
public TrackingExecutor(ExecutorService exec) {
this.exec = exec;
}
public void shutdown() {
exec.shutdown();
}
public List<Runnable> shutdownNow() {
return exec.shutdownNow();
}
public boolean isShutdown() {
return exec.isShutdown();
}
public boolean isTerminated() {
return exec.isTerminated();
}
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
return exec.awaitTermination(timeout, unit);
}
public List<Runnable> getCancelledTasks() {
if (!exec.isTerminated())
throw new IllegalStateException(/*...*/);
return new ArrayList<Runnable>(tasksCancelledAtShutdown);
}
public void execute(final Runnable runnable) {
exec.execute(new Runnable() {
public void run() {
try {
runnable.run();
} finally {
if (isShutdown()
&& Thread.currentThread().isInterrupted())
tasksCancelledAtShutdown.add(runnable);
}
}
});
}
}
Then he creates Crawler which uses TrackingExecutor:
crawler:
/**
* WebCrawler
* <p/>
* Using TrackingExecutorService to save unfinished tasks for later execution
*
* #author Brian Goetz and Tim Peierls
*/
public abstract class WebCrawler {
private volatile TrackingExecutor exec;
#GuardedBy("this") private final Set<URL> urlsToCrawl = new HashSet<URL>();
private final ConcurrentMap<URL, Boolean> seen = new ConcurrentHashMap<URL, Boolean>();
private static final long TIMEOUT = 500;
private static final TimeUnit UNIT = MILLISECONDS;
public WebCrawler(URL startUrl) {
urlsToCrawl.add(startUrl);
}
public synchronized void start() {
exec = new TrackingExecutor(Executors.newCachedThreadPool());
for (URL url : urlsToCrawl) submitCrawlTask(url);
urlsToCrawl.clear();
}
public synchronized void stop() throws InterruptedException {
try {
saveUncrawled(exec.shutdownNow());
if (exec.awaitTermination(TIMEOUT, UNIT))
saveUncrawled(exec.getCancelledTasks());
} finally {
exec = null;
}
}
protected abstract List<URL> processPage(URL url);
private void saveUncrawled(List<Runnable> uncrawled) {
for (Runnable task : uncrawled)
urlsToCrawl.add(((CrawlTask) task).getPage());
}
private void submitCrawlTask(URL u) {
exec.execute(new CrawlTask(u));
}
private class CrawlTask implements Runnable {
private final URL url;
CrawlTask(URL url) {
this.url = url;
}
private int count = 1;
boolean alreadyCrawled() {
return seen.putIfAbsent(url, true) != null;
}
void markUncrawled() {
seen.remove(url);
System.out.printf("marking %s uncrawled%n", url);
}
public void run() {
for (URL link : processPage(url)) {
if (Thread.currentThread().isInterrupted())
return;
submitCrawlTask(link);
}
}
public URL getPage() {
return url;
}
}
}
But I don't understand what is the exact chronology of calls of runnable.run(), exec.shutdownNow(), exec.awaitTermination(...), exec.getCancelledTasks(), tasksCancelledAtShutdown.add(runnable), the runnable completion and thread-interleaving, which leads to a race condition.
This is how I understand it. For example,TrackingExecutor is shutting down before CrawlTask exit, this task may be also recorded as a taskCancelledAtShutdown, because if (isShutdown() && Thread.currentThread().isInterrupted()) in TrackingExecutor#execute may be true , but in fact this task has completed.
private class CrawlTask implements Runnable {
public void run() {
for (URL link : processPage(url)) {
if (Thread.currentThread().isInterrupted())
return;
submitCrawlTask(link);
}
// May be here, trackingExecutor is shutting down.
// Actually this task has completed now.But this method did not exit.
}
}
public void execute(final Runnable runnable) {
exec.execute(new Runnable() {
public void run() {
try {
runnable.run();
} finally {
// isShutdown() && Thread.currentThread().isInterrupted() may be true
if (isShutdown()
&& Thread.currentThread().isInterrupted())
tasksCancelledAtShutdown.add(runnable);
}
}
});
}
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 am using JUnit v4 as a test framework. I wanted to know how to set timeout at runtime in Test Case?
I am using Parameterized test. In which I have a list of Scenario, which contains timeout value and some other fileds. Each of these Scenario may have different-2 timeouts.
The timeout parameter is not helping me to achieve this.
#Test(timeout = getTimeOut())
public void secureLoginWithLongUsername() {
// Test case goes here
}
private final long getTimeOut() {
// I am doing some processing here to calculate timeOut dynamically
long timeOut = scenario.getTimeOut();
return timeOut;
}
#Parameters
public static Collection<Scenario[]> getParameters() {
List<Scenario[]> scenarioList = new ArrayList<Scenario[]>();
Configuration config = new Configuration();
List<Scenario> scenarios = config.getScenarios();
for (Scenario scenario : scenarios) {
scenarioList.add(new Scenario[] { scenario });
}
return scenarioList;
}
public class Configuration {
private List<Scenario> scenarios;
//Some processing here
public List<Scenario> getScenarios() {
return scenarios;
}
}
public class Scenario {
private long timeOut;
private String name;
//Some more fields here
}
Please help me to fine out any alternative to set the timeout dynamically.
I think, you need to build it yourself, like:
private Timer timer;
#After
public void terminateTimeout() {
if (timer != null) {
timer.cancel();
timer = null;
}
}
#Test
public void testTimeout() throws Exception {
setTimeout(1000);
// run test...
}
private void setTimeout(int duration) {
final Thread currentThread = Thread.currentThread();
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
currentThread.interrupt();
}
}, duration);
}