I have an implementation like this which doesn't work. As you see, job takes ~5sec and should run on fixedRate 1sec. That means there should be ~5jobs running in parallel but Spring wait to finish a job before starts another one...
If I add second #Scheduled job 'schedule2' with the same and parameters, I have 2 different jobs running in parallel but never the same job. Is it somehow possible to achieve this?
#Scheduled(fixedRate = 1000)
private void schedule1() {
int index = atomicInteger1.addAndGet(1);
logger.info("Run Schedule1 nr.{} started at: {}", index, LocalDateTime.now());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
logger.info("Schedule1 nr.{} finished at: {}", index, LocalDateTime.now());
}
}
#Bean(destroyMethod = "shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(10);
}
Each scheduled task will never run in parallel in this case. That's because the task takes longer than the given fixedRate. Why? Because ScheduledExecutorService#scheduleAtFixedRate is called, and as the documentation says (bolded is mine):
... If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.
One way of solving this is by using #Async and #EnableAsync. Many examples are available in the Spring docs:
#EnableAsync
public class Example {
#Async
#Scheduled(fixedRate = 1000)
public void schedule1() throws InterruptedException {
Thread.sleep(5000);
}
}
If you really want to achieve what you want, you should manage the threads by your own, calling to a service from the job in a separate thread.. but I don't see a reason to do that at least you're only testing and playing with Jobs at home for pet projects.
Anyway, have a look at this:
https://www.baeldung.com/java-future
Related
I am having a class called JobManagement which has a job[] jobs and a ArrayBlockingQueue queue with the size of 2.
What i am trying to do:
I want to create for exaple 20 jobs. The Job class extends Thread and overrides the run method:
#Override
public void run() {
setStatus(EnumStatus.inProgress);
System.out.println(this.toString());
System.out.println("Working...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new AuftragException();
}
setStatus(EnumStatus.done);
I wann to fill my queue with 2 jobs, call the run method on them, and repeat until all jobs from the job[] jobs are done.
I am currently thinking of a method startWork() in the class JobManagement which does the following:
for (Job j : jobs) {
while (!queue.offer(j)) {
queue.poll().start();
}
I do not limit Java to only use 2 threads here, am i?
Edit:
Using Executor.Service with a fixed threadpool solved my issue.
I am developing an API. This API needs to do 2 DB queries to get the result.
I tried following strategies:
Used callable as return type in Controller.
Created 2 threads in Service (use Callable and CoundownLatch) to run 2 queries parallel and detect finishing time.
public class PetService {
public Object getData() {
CountDownLatch latch = new CountDownLatch(2);
AsyncQueryDBTask<Integer> firstQuery= new AsyncQueryDBTask<>(latch);
AsyncQueryDBTask<Integer> secondQuery= new AsyncQueryDBTask<>(latch);
latch.await();
}
public class AsyncQueryDBTask<T> implements Callable {
private CountDownLatch latch;
public AsyncQueryDBTask(CountDownLatch latch) { this.latch = latch;}
#Override
public T call() throws Exception {
//Run query
latch.countDown();
}
It worked fine but I feel that I am breaking the structure of Spring somewhere.
I wonder what is the most efficient way to get data in Spring 4.
-How to know both of 2 threads that run own query completed their job?
-How to control thread resource such as use and release thread?
Thanks in advance.
You generally don't want to create your own threads in an ApplicationServer nor manage thread lifecycles. In application servers, you can submit tasks to an ExecutorService to pool background worker threads.
Conveniently, Spring has the #Async annotation that handles all of that for you. In your example, you would create 2 async methods that return a Future :
public class PetService {
public Object getData() {
Future<Integer> futureFirstResult = runFirstQuery();
Future<Integer> futureSecondResult = runSecondQuery();
Integer firstResult = futureFirstResult.get();
Integer secondResult = futureSecondResult.get();
}
#Async
public Future<Integer> runFirstQuery() {
//do query
return new AsyncResult<>(result);
}
#Async
public Future<Integer> runSecondQuery() {
//do query
return new AsyncResult<>(result);
}
}
As long as you configure a ThreadPoolTaskExecutor and enable async methods, Spring will handle submitting the tasks for you.
NOTE: The get() method blocks the current thread until a result is returned by the worker thread but doesn't block other worker threads. It's generally advisable to put a timeout to prevent blocking forever.
I have written a piece of code . How can I get that code to run for certain duration repeatedly, say for 10 second?
The ExecutorService seems to provide methods which execute tasks until they are either completed or else a timeout occurs (such as the invokeAll).
You can give a try to Quartz Job Scheduler
Quartz is a richly featured, open source job scheduling library that
can be integrated within virtually any Java application - from the
smallest stand-alone application to the largest e-commerce system.
Quartz can be used to create simple or complex schedules for executing
tens, hundreds, or even tens-of-thousands of jobs; jobs whose tasks
are defined as standard Java components that may execute virtually
anything you may program them to do. The Quartz Scheduler includes
many enterprise-class features, such as support for JTA transactions
and clustering.
If you are familiar with Cron in Linux , this will be a cakewalk for you .
Use a worker and start it in a thread, wait in the main thread for the specific time and stop the worker after this.
MyRunnable task = new MyRunnable();
Thread worker = new Thread(task);
// Start the thread, never call method run() direct
worker.start();
Thread.sleep(10*1000); //sleep 10s
if (worker.isAlive()) {
task.stopPlease(); //this method you have to implement
}
Not too sure why people downvoted the question. Be sure to in the future provide some sample code. Your answer however is simple here. Create a new thread to watch the wait. In simple code:
public class RunningClass {
public static void runThis(){
TimerThread tt = new TimerThread();
tt.timeToWait = 10000;
new Thread(tt).start();
while (!TimerThread.isTimeOver){
\\Code to execute for time period
}
}
class TimerThread implements Runnable {
int timeToWait = 0;
boolean isTimeOver = false;
#override
public void run(){
Thread.sleep(timeToWait);
}
}
The code above can be put in the same class file. Change the 10000 to whatever time you require it to run for.
You could use other options, but it would require you to have knowledge on workers and tasks.
not sure what was the exact requirement, but
if your req was to cancel only a long running task
you could use ExecutorService & Future (in jdk 5) as follows.
ExecutorService fxdThrdPl = Executors.newFixedThreadPool(2);
// actual task .. which just prints hi but after 100 mins
Callable<String> longRunningTask = new Callable<String>() {
#Override
public String call() throws Exception {
try{
TimeUnit.MINUTES.sleep(100); // long running task .......
}catch(InterruptedException ie){
System.out.println("Thread interrupted");
return "";
}
return "hii"; // result after the long running task
}
};
Future<String> taskResult = fxdThrdPl.submit(longRunningTask); // submitting the task
try {
String output = taskResult.get(***10**strong text**, TimeUnit.SECONDS***);
System.out.println(output);
} catch (InterruptedException e) {
} catch (ExecutionException e) {
} catch (TimeoutException e) {
***taskResult.cancel(true);***
}
I am running a scheduled task in the web application using the java SingleThreadScheduledExecutor
The problem I have is - How do I identify whether the scheduler is still running and has not crashed?
Is there a better way of doing it rather than having another scheduler to check this particular scheduler
there is actually a way to check
public class TaskSchedulerService{
private final ThreadPoolTaskScheduler taskScheduler; //initialize it here or in constructor
private Map<String,ScheduledFuture<?>> scheduleMap = new ConcurrentHashMap<>();
public TaskSchedulerServiceImpl() {
this.schedulerName = schedulerName;
taskScheduler.initialize();
}
public boolean isScheduled(String taskId) {
final ScheduledFuture<?> exits = scheduledTasks.get(taskId);
return exits != null && exits.isDone();
}
public ScheduledFuture<?> schedule(String taskId, Runnable task, Date date) {
ScheduledFuture<?> scheduled = scheduleMap.get(taskId);
if (scheduled==null ) {
ScheduledFuture<?> future = taskScheduler.schedule(task, date);
scheduleMap.put(taskId, future);
return future;
} else {
// log it is already scheduled
return scheduled;
}
}
i know it is too late but i hope others can get benefit from it
The logic behind the implementation is whenever you are trying to schedule a task, you will have to add it to the map with the taskId as well, in this case it is better to find any task if exists in MAP or if needed remove it as well as checking if that task is done or not
The answer depends on what your scheduler does really. For instance, you can produce a file or update a field in a db or such thing that can be checked and the time interval (from now to last update) can be calculated. In your case, if the time interval of file creation or db updated is more than half an hour this means the job did stop. But notice that scheduled jobs are meant to last forever like love.
I've got working spring MVC app and what I'm trying to do next is to start or submit a background task from my app.
Basically I'd like to keep the task going until it completes even if the user decides to do something else on the app.
But also I'd like to stop/kill/pause the task if I needed to. Since I haven't done this before I'm looking for a good/better way to do this.
I found these to be useful:
http://blog.springsource.com/2010/01/05/task-scheduling-simplifications-in-spring-3-0/
How do you kill a thread in Java?
Java threads: Is it possible view/pause/kill a particular thread from a different java program running on the same JVM?
So I wanted to use #Async task to submit my background task, but wanted to use threads' id to obtain it later on and stop it if needed?
Is this the right approach? I don't have any experience with multithreading so I'm here to listen.
Code update :
public interface Worker {
public void work();
public void cancel();
}
implementation :
#Component("asyncWorker")
public class AsyncWorker implements Worker {
#Async
public void work() {
String threadName = Thread.currentThread().getName();
System.out.println(" " + threadName + " beginning work");
try {
Thread.sleep(10000); // simulates work
} catch (InterruptedException e) {
System.out.println("I stopped");
}
System.out.println(" " + threadName + " completed work");
}
public void cancel() { Thread.currentThread().interrupt(); }
}
Controller for testing purposes :
#ResponseBody
#RequestMapping("/job/start")
public String start() {
asyncWorker.work();
return "start";
}
#ResponseBody
#RequestMapping("/job/stop")
public String stop() {
asyncWorker.cancel();
return "stop";
}
When I visit /job/start, I can't execute more that one task simultaneously. The other one starts to execute only after first one has completed
Also when I visit /job/stop the process isn't stopped, what am I missing here?
Using thread ID is too low level and brittle. If you decided to use #Async annotation (good choice) you can use Future<T> to control the task execution. Basically your method should return a Future<T> instead of void:
#Async
public Future<Work> work() //...
Now you can cancel() that Future or wait for it to complete:
#ResponseBody
#RequestMapping("/job/start")
public String start() {
Future<Work> future = asyncWorker.work();
//store future somewhere
return "start";
}
#ResponseBody
#RequestMapping("/job/stop")
public String stop() {
future.cancel();
return "stop";
}
The tricky part is to store the returned future object somehow so it is available for subsequent requests. Of course you cannot use a field or ThreadLocal. You can put in session, note however that Future is not serializable and won't work across clusters.
Since #Async is typically backed by thread pool, chances are your tasks didn't even started. Cancelling will simply remove it from the pool. If the task is already running, you can the isInterrupted() thread flag or handle InterruptedException to discover cancel() call.