Trying do some debouncing, the use case is that client may send multiple requests to server in short interval unnecessarily. The requests are all the same but response is different at the time of the server processing, so the last response is the one to use.
With following code if do not always create a new timer, after timer.cancel(), the timer.schedule() will crash with "Timer already cancelled.".
Can't the timer be reused?
Is there better way to do the debouncing without using timer?
private Timer debouncerTimer = new Timer();
synchronized void debounceRequest() {
debouncerTimer.cancel();
//debouncerTimer = new Timer(); //<== without this one it crashes with IllegalStateException("Timer already cancelled.")
debouncerTimer.schedule(new TimerTask() {
#Override
public void run() {
doSendRequest();
}
}, 150);
}
A facility for threads to schedule tasks for future execution in a
background thread. Tasks may be scheduled for one-time execution, or
for repeated execution at regular intervals.
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Timer.html
Here is an example using ScheduledExecutorService that could work:
private ScheduledExecutorService debouncer = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> scheduledRequest;
synchronized void debounceRequest() {
if (scheduledRequest != null) {
scheduledRequest.cancel(false);
}
scheduledRequest = debouncer.scheduleWithFixedDelay(this::doSendRequest, 0, 150, TimeUnit.MILLISECONDS);
}
private void doSendRequest() {
//Send request stuff here
}
Related
I am trying to make the bot show it's server count, which gets updated every 20 seconds of so!
I have tried to put it in a loop after an await ready event:
public void onReady(ReadyEvent event) {
while (true) {
TimeUnit.SECONDS.sleep(20)
event.JDA().getPresence().setGame(Game.watching(event.getJDA().getGuilds().size() + "servers"));
}
}
This has succeeded in displaying the amount of servers it joined but this stopped any other code from being run.
So how can I do this without the rest of the program being ignored?
You should try setting an interval and doing the update on it
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
Runnable task = () -> {
event.JDA().getPresence().setGame(Game.watching(event.getJDA().getGuilds().size() + "servers"));
};
executor.scheduleWithFixedDelay(task, 0, 20,TimeUnit.SECONDS);
or using Timer
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
event.JDA().getPresence().setGame(Game.watching(event.getJDA().getGuilds().size() + "servers"));
}
}, 0, 20000 );
setting it inside a while(true) makes it stop there, because it extecutes on the main thread whitout creating a new one.
This is probably a very easy question but, How do I use a timer to run code again and again until a boolean value e.g. Testing is equal to true?
Obviously I would use a while loop but I don't want it to stop the rest of the work taking place on the main ui thread
If your process is running simultaneously, use a Handler and use its postDelayed(Runnable, long) to post a callback implementing the Runnable interface.
A rather naive example:
final handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
if (<EXPRESSION>) {
// Evaluated true, do your stuff and exit the polling loop.
} else {
handler.postDelayed(this, <TIMEOUT>);
}
}
handler.postDelayed(r, <TIMEOUT>);
You can use AlarmManager class to manage your thread. its simple to use.
for more info you can visit Android SDK Doc
timer=new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// Do your task
if(flagIsOn)
{
timer.cancel();
timer.purge();
}
}
}, 0, 1000);
I want,in my mainactivity,to start a thread that does some stuff every x seconds.
is this aproach correct?
taken from my oncreate method:
Thread thread = new Thread()
{
#Override
public void run() {
try {
while(true) {
sleep(5000);
do stuff
};
thread.start();
if it's relevant it starts a videoplayer and checks its buffer every 5 seconds.
You can create flexible and effective timer using Java's ExecutorService:
// create executor that consists of 1 thread
final ExecutorService e = Executors.newScheduledThreadPool(1);
// schedule it to execute every 5000 ms starting from now
((ScheduledExecutorService) e).scheduleAtFixedRate(new Runnable(){
#Override
public void run() {
// your repeating task
}
}, 0, 5000, TimeUnit.MILLISECONDS);
This approach is more flexible and, if Java docs don't lie, more precise since it is independent on system clock changes.
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html
I'm using Timer() due to its accuracy but works in the same was as PostDelayed Handler. It's called only once. Here is the Timer code:
public void setWFT() {
WFT = new Timer();
WFT.schedule(new TimerTask() {
#Override
public void run() {
WFTTimerMethod();
}
}, 60000); // 60 seconds delay
}
private void WFTTimerMethod() {
this.runOnUiThread(Timer_Tick);
}
private Runnable Timer_Tick = new Runnable() {
public void run() {
// My commands here
}
};
This only calls run() once after 60 seconds once the Timer is started. Sometimes, I have to cancel the Timer to Update the delay (replace the "60000" value). To start the Timer again, I simply recreate the Timer by calling WFT() again with the new delay value.
Problem is, when I cancel the timer using:
WFT.cancel();
WFT.purge();
The Timer does not start. the run() doesn't execute when it's supposed to. So my question is do I use cancel() and purge() or just cancel()?
Thanks
From the Java API on purge():
Most programs will have no need to call this method. It is designed for use by the rare application that cancels a large number of tasks. Calling this method trades time for space: the runtime of the method may be proportional to n + c log n, where n is the number of tasks in the queue and c is the number of cancelled tasks.
So you only need to call cancel()
from cancel() documentation :
No more tasks may be scheduled on this Timer.
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.....
*/
}
}