I have a task I want to run where the delay will keep changing (i.e. - no fixed interval).
I want a thread and loops infinitely that finds the delay value, inputs this into the executor and then once that task is done find the new delay value etc..
My current 'basic' implementation:
long targetTime = findNextTime()/1000;
long currentTime = System.curentTimeMillis()/1000;
delay = targetTime - currentTime;
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(3);
Runnable task = new Runnable() {
public void run() {
System.out.println("Test Task");
ScheduledFuture<?> future = scheduler.schedule(this, delay, TimeUnit.SECONDS);
}
}
How can I get it to find the new delay and keep repeating this task?
Should I poll for future to be done and then do a recursive loop? I try this and I get an error.
There are some answer to resolve this.Reinitialize fix delay in ScheduledExecutorService and
How to change Spring's #Scheduled fixedDelay at runtime
here i support another method to realize this-repeated submit task to ExecutorService
class Task implements Runnable {
private static Random random = new Random();
private ExecutorService executor;
public Task(ExecutorService executor) {
this.executor = executor;
}
#Override
public void run() {
try {
System.out.println(System.currentTimeMillis() + " Hello World");
TimeUnit.MILLISECONDS.sleep(random.nextInt() % 100);
executor.execute(this);
} catch (Exception e) {
}
}
}
Related
I'm using a task that creates other tasks. Those tasks in turn may or may not create subsequent tasks. I don't know beforehand how many tasks will be created in total. At some point, no more tasks will be created, and all the task will finish.
When the last task is done, I must do some extra stuff.
Which threading mechanism should be used? I've read about CountDownLatch, Cyclic Barrier and Phaser but none seem to fit.
I've also tried using ExecutorService, but I've encountered some issues such as the inability to execute something at the end, and you can see my attempt below:
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
public class Issue {
public static void main(String[] args) throws InterruptedException {
var count = new AtomicInteger(1);
var executor = Executors.newFixedThreadPool(3);
class Task implements Runnable {
final int id = count.getAndIncrement();
#Override
public void run() {
try {
MILLISECONDS.sleep((long)(Math.random() * 1000L + 1000L));
} catch (InterruptedException e) {
// Do nothing
}
if (id < 5) {
executor.submit(new Task());
executor.submit(new Task());
}
System.out.println(id);
}
}
executor.execute(new Task());
executor.shutdown();
// executor.awaitTermination(20, TimeUnit.SECONDS);
System.out.println("Hello");
}
}
This outputs an exception because tasks are added after shutdown() is called, but the expected output would be akin to:
1
2
3
4
5
6
7
8
9
Hello
Which threading mechanism can help me do that?
It seems pretty tricky. If there is even a single task that's either in the queue or currently executing, then since you can't say whether or not it will spawn another task, you have no way to know how long it may run for. It may be the start of a chain of tasks that takes another 2 hours.
I think all the information you'd need to achieve this is encapsulated by the executor implementations. You need to know what's running and what's in the queue.
I think you're unfortunately looking at having to write your own executor. It needn't be complicated and it doesn't have to conform to the JDK's interfaces if you don't want it to. Just something that maintains a thread pool and a queue of tasks. Add the ability to attach listeners to the executor. When the queue is empty and there are no actively executing tasks then you can notify the listeners.
Here's a quick code sketch.
class MyExecutor
{
private final AtomicLong taskId = new AtomicLong();
private final Map<Long, Runnable> idToQueuedTask = new ConcurrentHashMap<>();
private final AtomicLong runningTasks = new AtomicLong();
private final ExecutorService delegate = Executors.newFixedThreadPool(3);
public void submit(Runnable task) {
long id = taskId.incrementAndGet();
final Runnable wrapped = () -> {
taskStarted(id);
try {
task.run();
}
finally {
taskEnded();
}
};
idToQueuedTask.put(id, wrapped);
delegate.submit(wrapped);
}
private void taskStarted(long id) {
idToQueuedTask.remove(id);
runningTasks.incrementAndGet();
}
private void taskEnded() {
final long numRunning = runningTasks.decrementAndGet();
if (numRunning == 0 && idToQueuedTask.isEmpty()) {
System.out.println("Done, time to notify listeners");
}
}
public static void main(String[] args) {
MyExecutor executor = new MyExecutor();
executor.submit(() -> {
System.out.println("Parent task");
try {
Thread.sleep(1000);
}
catch (Exception e) {}
executor.submit(() -> {
System.out.println("Child task");
});
});
}
}
If you change your ExecutorService to this:
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(3);
You could then use the count functions to wait:
while(executor.getTaskCount() > executor.getCompletedTaskCount())
{
TimeUnit.SECONDS.sleep(10L);
}
executor.shutdown();
System.out.println("Hello");
How would I create a thread that will execute after a delay of s seconds?
I would like other processes to run while the thread is waiting.
For example, I would like to create the thread, then print out several other strings, then after s seconds, the thread will run.
What I don't need is the whole program to wait for s seconds, then everything happens. I need processes to run while the delay is ticking.
Thanks!
~Java preferred
Use a ScheduledExecutorService. See the example below.
System.out.println("some stuff");
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
final Runnable task = new Runnable() {
#Override
public void run() {
System.out.println("do something");
}
};
Future<?> futureHandle = scheduler.scheduleWithFixedDelay(task, 10, 10, TimeUnit.SECONDS);
System.out.println("some other stuff");
The task is scheduled with a fixed delay of 10 seconds, so you'll get output for the print statements not in the Runnable followed by the one in the Runnable every 10 seconds.
The output in this example is
some stuff
some other stuff
do something
do something
...
with the "do something" lines occurring at 10 sec. intervals after an initial 10 sec. delay.
To stop it, you can create a "stop" task to put some kind of logic in, and register that.
final Runnable stopTask = new Runnable() {
#Override
public void run() {
futureHandle.cancel(true); // true: interrupt if necessary
}
};
long delay = // some number, how long to wait before invoking the stop task
scheduler.schedule(stopTask, delay, TimeUnit.SECONDS).get(); // wait if necessary and get the future result
scheduler.shutdown(); // shutdown on completion
EDIT
If you just need the task to run once, as pointed out in the comments, consider a TimerTask:
final Timer timer = new Timer();
final TimerTask task = new TimerTask() {
#Override
public void run() {
System.out.println("timer task");
timer.cancel(); // stop timer after execution
}
};
timer.schedule(task, 1000); // schedule task with delay of 1000ms
I would suggest you to take look into quartz scheduler. This is very powerful and does almost similar tasks like unix cron in java environment.
There are bunch of tutorials online for quartz that you can always look into.
Here is one working example with Thread.sleep():
public class DelayThread implements Runnable {
private final int DELAY;
public DelayThread(int delay) {
this.DELAY = delay;
}
#Override
public void run() {
try {
Thread.sleep(DELAY);
System.out.println("task executed");
} catch (InterruptedException ex) {
System.out.println("interrupted");
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new DelayThread(2000));
thread1.start();
Thread.sleep(500);
Thread thread2 = new Thread(new DelayThread(2000));
thread2.start();
System.out.println("All threads are started");
}
}
My goal is to schedule a recurrent job that happens on a non-even rate. I am going to migrate from first snippet to the second:
1st:
Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (msg.what == MSG1) {
//recurrent job here
long nextTime = nextTime();
sendMessageAtTime(obtainMessage(MSG1), nextTime);
}
}
}
};
2nd:
ScheduledExecutorService mExecutor;
while (true){
mExecutor.schedule(new Callable() {
public Object call() throws Exception {
long startTime = SystemClock.uptimeMillis();
//recurrent job here
delay = nextTime() - startTime ;
return true;
}
}, delay, TimeUnit.MILLISECONDS);
}
My questions are:
1- is it true in the first snippet that the thread, to which the mHandler is referring, is free between jobs to do other tasks or handle other messages?
2- However in the second snippet, Thread is always busy doing the loop. right?
3- How can I rewrite the second code so that I won't loose thread activity between jobs (in delays)?
Any help is highly appreciated
Your second code won't work as expected. After the first task has been scheduled and is waiting to be executed, the while loop continues to schedule more tasks, all of them with the same delay. So you'll end up having thousands, probably millions of tasks. And of course, because the main thread is running an infinite loop without any wait, it is busy all the time. This is probably not what you want.
You should better use a simliar approach than the handler uses above:
final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.schedule(() -> {
// do work
// reschedule
executor.schedule(this, nextTime() - System.currentTimeMillis());
}, delay, TimeUnit.MILLISECONDS);
(Of course you should also check that the delay you specify when rescheduling is not negative).
Update: If you need to process the result of each execution individually, another approach similar to your second code example is possibly what you want. It schedules the task executions insisde a loop and hands over the result to a Consumer, as soon as it is available. (Note the future.get() inside the loop which causes the looping thread to pause until the task is done).
public static <T> void schedule(ScheduledExecutorService scheduler,
Schedule schedule, Callable<T> task, Consumer<? super T> consumer)
throws InterruptedException, ExecutionException {
while (true) {
if (Thread.interrupted()) throw new InterruptedException();
long delay = schedule.nextTime() - System.currentTimeMillis();
if (delay < 0) continue; // skip this step
ScheduledFuture<? extends T> future = scheduler.schedule(task,
delay, schedule.getUnit());
consumer.accept(future.get());
}
}
Also note the interruption check, so that other threads can stop execution by interrupting the looping thread. This simplifies the usage of this method inside another task in case you want to run it on a background thread too.
Schedule could be a functional interface that provides access to the scheduling information:
#FunctionalInterface
public interface Schedule {
long nextTime();
default TimeUnit getUnit() { return TimeUnit.MILLISECONDS; }
}
Btw.: The android.os.Handler is a very nice way to do what you want in android. So you should only migrate to ScheduledExecutorService if you really need its features (e.g. getting a Future result).
public class RecurrentJobThatHappensOnANonEvenRate {
/**
* Consider you have your job defined as below
*/
abstract class TheJob implements Runnable {
#Override
public void run() {
long startTime = System.currentTimeMillis();
doRecurrentJob();
schedule(nextTime() - startTime);
}
void doRecurrentJob() {
// Do the job
}
long nextTime() {
// calculate next execution time
long randomDelay = Math.round(5000 + Math.random() * 5000);
return System.currentTimeMillis() + randomDelay;
}
public abstract void schedule(long delay);
};
/**
* Example using `ScheduledExecutorService`.
*/
public void exampleWithScheduledExecutorService() {
TheJob theJob = new TheJob() {
private final ScheduledExecutorService executor =
Executors.newScheduledThreadPool(1);
#Override
public void schedule(long delay) {
executor.schedule(this, delay, TimeUnit.MILLISECONDS);
}
};
theJob.schedule(1500);
}
/**
* Example with `Handler` and using already existing `Thread` with
* `Looper` (most probably the main looper).
*/
public void exampleWithHandlerAndMainLooper() {
TheJob theJob = new TheJob() {
private final Handler handler =
// new Handler();
// or if you are not in the main thread:
new Handler(Looper.getMainLooper());
#Override
public void schedule(long delay) {
handler.postDelayed(this, delay);
}
};
theJob.schedule(1500);
}
/**
* Example with `Handler` and `HandlerThread` (a convenience thread
* class with looper).
*/
public void exampleWithHandlerAndHandlerThreadsLooper() {
TheJob theJob = new TheJob() {
private final HandlerThread handlerThread;
private final Handler handler;
private final long killThreadAt;
{
handlerThread = new HandlerThread("myThread");
// handler thread must be quit when you no longer use it.
// see nextTime() method below.
killThreadAt = System.currentTimeMillis() + 30000;
// alternatively you can set it to be a daemon thread.
// handlerThread.setDaemon(true);
handlerThread.start();
handler = new Handler(handlerThread.getLooper());
}
#Override
public void schedule(long delay) {
handler.postDelayed(this, delay);
}
#Override
long nextTime() {
long nextTime = super.nextTime();
if(nextTime() > killThreadAt) {
handlerThread.quit();
}
return nextTime;
}
};
theJob.schedule(1500);
}
}
I had some similar issues .. I was trying to schedule different jobs at different rates and I found using the Quartz Scheduler library to handle all my scheduling problems a real relieve :)
For your problem: firing a job at a non-even rate, you could easily implement a TriggerListener and on completion reschedule the same job at nextTime()
The Quartz Scheduler easily integrates with Spring, Maven and has handles for all kind of scenarios like misfired jobs or thread exceptions.
Simple example (from the docs)
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
// define the job and tie it to our HelloJob class
JobDetail job = newJob(HelloJob.class)
.withIdentity("job1", "group1")
.build();
// compute a time that is on the next round minute
int minutesInterval = nextTime();
// Trigger the job to run on the next round minute and repeat it forever
Trigger trigger = newTrigger()
.withIdentity("trigger1", "group1")
.withSchedule(
simpleSchedule()
.withIntervalInMinutes(minutesInterval)
.repeatForever()
)
.build();
// Tell quartz to schedule the job using our trigger
sched.scheduleJob(job, trigger);
sched.start();
How would I have this method run every couple of seconds in a recursive function.
I want the i variable to update by 1 every couple of seconds than print it to the console.
In javascript I could use setTimeout is there a method like the javascript setTimeout in Java?
final i = 0;
public void timerActions() {
i = i + 1;
System.out.println(i);
}
try with Timer
Timer timer = new Timer("Display Timer");
TimerTask task = new TimerTask() {
#Override
public void run() {
timerActions();
}
};
// This will invoke the timer every second
timer.scheduleAtFixedRate(task, 1000, 1000);
}
You should use ScheduledExecutorService for that.
Update per Peter Lawrey comment (thanks):
Methods :
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit);
and
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit);
can be used in order to achieve your desired behavior.
You can put the Thread to sleep after execution if it's just a simple application which just has to "run slower".
For example:
final i = 0;
public void timerActions() {
i++;
System.out.println(i);
Thread.sleep(1000);
}
1000 in the parentheses means 1000ms=1second - the amount of time in which the thread sleeps.
This is a simple way to do it, but be aware that in larger multi-threaded applications you have to take into acount thread safety and related problems.
Documentation for Thread.sleep()
public class TimedAction
{
public static void main(String[] args) throws Exception
{
System.out.println("begin");
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
Runnable command = new Runnable()
{
private int i = 0;
#Override
public void run()
{
// put your logic HERE
System.out.println(i++);
}
};
// execute command, immediately (0 delay), and every 2 seconds
executor.scheduleAtFixedRate(command, 0, 2, TimeUnit.SECONDS);
System.in.read();
executor.shutdownNow();
executor.awaitTermination(5, TimeUnit.SECONDS);
System.out.println("end");
}
}
This will print "Counting..." on every 2 seconds
import java.util.Timer;
import java.util.TimerTask;
public class MyTimerTask extends TimerTask {
private int counter = 0;
public void run() {
counter++;
if (counter <= 3) {
System.out.println("Counting - counter = " + counter);
} else {
System.out.println("Stopping timer execution");
this.cancel();
}
}
public static void main(String[] args) {
Timer timer = new Timer("TimerThreadName");
MyTimerTask task = new MyTimerTask();
// void java.util.Timer.schedule(TimerTask task, long delay, long period)
timer.schedule(task, 0, 2000);
}
}
I'm trying to use a timer to schedule a recurring event in an application. However, I want to be able to adjust the period at which the event fires in real time (according to the users input).
For example:
public class HelperTimer extends TimerTask
{
private Timer timer;
//Default of 15 second between updates
private int secondsToDelay = 15;
public void setPeriod(int seconds)
{
this.secondsToDelay = seconds;
long delay = 1000; // 1 second
long period = 1000*secondsToDelay; // seconds
if (timer != null)
{
timer.cancel();
}
System.out.println(timer);
timer = new Timer();
System.out.println(timer);
timer.schedule(this, delay, period);
}
public int getPeriod()
{
return this.secondsToDelay;
}
}
I then start a new instance of this class and call its set period function. However, when I do that, I get an Illegal state exception. You can see the System.out.println(timer); in there because I'm checking, and yep sure enough, they are two different timers... so why am I getting an IllegalStateException when I try to run a schedule call on a brand new Timer instance!?!?!?!
java.util.Timer#c55e36
java.util.Timer#9664a1
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Task already scheduled or cancelled
at java.util.Timer.sched(Unknown Source)
at java.util.Timer.schedule(Unknown Source)
at HelperTimer.setPeriod(HelperTimer.java:38)
You can't reuse a TimerTask as you're doing here.
Relevant porition of Timer:
private void sched(TimerTask task, long time, long period) {
if (time < 0)
throw new IllegalArgumentException("Illegal execution time.");
synchronized(queue) {
if (!thread.newTasksMayBeScheduled)
throw new IllegalStateException("Timer already cancelled.");
synchronized(task.lock) {
//Right here's your problem.
// state is package-private, declared in TimerTask
if (task.state != TimerTask.VIRGIN)
throw new IllegalStateException(
"Task already scheduled or cancelled");
task.nextExecutionTime = time;
task.period = period;
task.state = TimerTask.SCHEDULED;
}
queue.add(task);
if (queue.getMin() == task)
queue.notify();
}
}
You'll need to refactor your code so that you create a new TimerTask, rather than re-using one.
It seems odd to me to have a TimerTask with its own Timer inside it. Bad design. I'd totally separate the two and have the TimerTask implementation be handed off to a Timer, and put all that logic about fiddling with the period inside another class that provides an interface for doing so. Let that class instantiate the Timer and TimerTask and send them off to do their work.
You can use ScheduledExecutorService, which allows you to schedule the same task multiple times without using scheduleAtFixedRate. Here's a quick example:
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
Runnable timerTask = new Runnable() {
#Override
public void run() {
// Do something
System.out.println("Task run!");
// Schedule again
executorService.schedule(this, 15, TimeUnit.SECONDS);
}
};
// Schedule
executorService.schedule(timerTask, 15, TimeUnit.SECONDS);
In this exmaple, "Executed...." will be printed after 4 seconds of delay. After that, it will be printed continuously every 3 seconds:
import java.util.*;
class TimeSetting {
public static void main(String[] args) {
Timer t = new Timer();
TimerTask time = new TimerTask() {
public void run() {
System.out.println("Executed......");
}
};
t.scheduleAtFixedRate(time, 4000, 3000);
/*
* The task will be started after 4 secs and
* for every 3 seconds the task will be continuously
* executed.....
*/
}
}