Right now I have a CountDownTimer that ticks like this:
MyTimer(60000, 1);
So it ticks down 60 seconds with an interval of 1ms.
I am signaling bpm's in my timer.
This is done by dividing every minute by a bpm-number:
public void onTick(long millisLeft) {
if (TimeUnit.MILLISECONDS.toSeconds(millisLeft) % (60 / bpm) == 0) {
doSignal();
}
}
This works great, but ONLY if the timer is set to interval 1000
MyTimer(60000, 1000);
That means it will tick once every second (every 1000ms). But I need it to tick at 1ms.
The problem with my condition is that if the timer ticks at an interval of 1ms. It will start the signal when supposed to - but repeat rapidly.
If interval is 1000ms and bpm is set to 20, it will beep every third second (60/20 == 3). If the interval is set to 1ms, it will start beeping every third second - and beep repeatedly through that second.
So somehow my condition is true within a larger span than I intended with 1ms ticker interval.
How do I design my condition so it will fire only once every (60 / bpm) seconds with the timer at an interval of 1ms?
TimeUnit.MILLISECONDS.toSeconds(millisLeft) returns 57 for all 57000 <= millisLeft <= 57999 so within that second you get 1000 doSignal calls (as 57 % (60/20) == 0). And the same goes on for 54, 51, ... . To avoid this you could use this expression instead millisLeft % (60000/20) == 0.
Related
I'm creating a simple simulation of gas station as homework. The total duration of the simulation is the week. Filling cars is approximately 3 minutes depending on the type of fuel. Cars may be collected in a queue. Now the question. I know how to implement these methods, but have no idea how to simulate a period of time without methods like a Thread.sleep().
P.S. I'm using JavaFX framework for this task. Cars are represented as javafx.scene.shape.Rectangle and their movements through Tranlsate methods. Dispensers too.
The Thread.sleep() method accepts a millisecond value. Basically, you can run an update and then calculate how long you need to sleep until the next update.
You can measure real time elapsed with System.nanoTime(). Make sure your class implements Runnable. Inside the run method, stick a while loop which contains an update() method to update the cars. Get nano time at the start and end of the loop, subtracting the two which gives you elapsed time. Subtract the elapsed time from the time you want each update to take, then sleep the thread. I think that is really all you need.
Here is the code:
public void run() {
int updatesPerSecond = 5;
/* The target time is the time each update should take.
* You want the target time to be in milliseconds.
* so 5 updates a second is 1000/5 milliseconds. */
int targetTime = 1000 / updatesPerSecond;
long currentTime;
long lastTime = System.nanoTime();
long elapsedTime;
long sleepTime;
while (running) {
// get current time (in nanoseconds)
currentTime = System.nanoTime();
// get time elapsed since last update
elapsedTime = currentTime - lastTime;
lastTime = currentTime;
// run your update
update();
// compute the thread sleep time in milliseconds.
// elapsed time is converted to milliseconds.
sleepTime = targetTime - (elapsedTime / 1000000000);
// don't let sleepTime drop below 0
if (sleepTime < 0) {
sleepTime = 1;
}
// attempt to sleep
try {
Thread.sleep(sleepTime);
} catch(Exception e) {
e.printStackTrace();
}
}
}
Within JavaFX framework,
you can simply use PauseTransition to simulate periodic time elapsing. On end of every period update scene graph elements' states. If you are going to change some properties of some node and do various animations you may utilize other types of Transitions. For more fine grained control you can use Timeline with its KeyFrames.
I am making listview with timers, each with different deadline depending on the database(similar to auction)
Time now = new Time();
now.setToNow();
now.normalize(true);
nowMillis = now.toMillis(true);
.
.
String endtime = a.get(position).get(TAG_ENDTIME);
Integer timeSecond = Integer.parseInt(endtime.substring(17, 19));
Integer timeMinute = Integer.parseInt(endtime.substring(14, 16));
Integer timeHour = Integer.parseInt(endtime.substring(11, 13));
Integer timeDay = Integer.parseInt(endtime.substring(0, 2));
Integer timeMonth = Integer.parseInt(endtime.substring(3, 5)) - 1;
Integer timeYear = Integer.parseInt(endtime.substring(6, 10));
Time future = new Time();
future.set(timeSecond, timeMinute, timeHour, timeDay, timeMonth, timeYear);
future.normalize(true);
long futureMillis = future.toMillis(true);
long interval = futureMillis - nowMillis;
new CountDownTimer(interval,1000)
{
#Override
public void onTick(long millisUntilFinished)
{
Long interval = millisUntilFinished;
int days = (int) ((millisUntilFinished / 1000) / 86400);
int hours = (int) (((millisUntilFinished / 1000) - (days * 86400)) / 3600);
int minutes = (int) (((millisUntilFinished / 1000) - (days * 86400) - (hours * 3600)) / 60);
int seconds = (int) ((millisUntilFinished / 1000) % 60);
String countdown = String.format("%dd %dh %dm %ds", days, hours, minutes, seconds);
holder.duration.setText(countdown);
}
#Override
public void onFinish()
{
// TODO Auto-generated method stub
holder.duration.setText(TimeUp);
}
}.start();
That code works almost perfectly when there is only one instance.
However the problem arise when there is several instance, around 4-5 timer running at the same time
Several/all the countdown will start to flicker, be it seconds, minutes, hours, or days.
e.g. one of my timer flicker between 27d 11h 54m 50s and 0d 23h 47m 0s
Since this occur on both on emulator and on my device, it seems to be my code's flaw, but I don't have a clue what could cause this.
I tried to change
holder.duration.setText(countdown) into holder.duration.setText(millisUntilFinished)
and the the countdown flickers between the desired duration and a huge, random number,
Please help.
You should use one TimerTask and put all your UI updates into that single timer instead running multiple CountDownTimers for essentially the same job since you're already doing all the math to determine when "time is up" for any particular item, you might just run one TimerTask and once a second have it update everything. CountDownTimer is useful for a single implementation count down because it does some built-in math, etc. You're redoing all that math, so you might as well use one instance of a regular TimerTask.
The implementation of CountDownTimer relays on scheduled delays in Handler messaging. A single countdown instance is unlikely to result in any bizarre behavior, but if you have several going that all supposed to "tick" when the system clock hits each second (the time in millis ends in "000" - once a second, and all at the same time), then those handlers will all try to fire simultaneously and inevitably fail.
If the UI or other process will likely delay some of these messages, even to the point where it will "skip ticks" to catch up. Also, that means that the next message delay could be only milliseconds from the next tick (i.e. if it's supposed to check every 1000 millis, but is delayed an additional 1990 millis, then it will skip a tick and also schedule the next message for 10 millis into the future.
I am looking for the best way in Java to monitor the computer clock (the minutes) and to fire off a method/thread every time it changes.
So if the time is 13:20 and it changes to 13.21 then do something. So any time there is a minute change some code gets fired.
What is the best way to listen to the minute section of the clock for changes ?
Thanks,
Richard
Find the current system time using System.currentTimeMillis()
Calculate how many milliseconds until the next minute
Schedule a TimerTask on a Timer to run in that number of milliseconds in the future
In that TimerTask's event handler schedule a new reoccurring TimerTask to run every 60,000 milliseconds.
int milisInAMinute = 60000;
long time = System.currentTimeMillis();
Runnable update = new Runnable() {
public void run() {
// Do whatever you want to do when the minute changes
}
};
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
update.run();
}
}, time % milisInAMinute, milisInAMinute);
// This will update for the current minute, it will be updated again in at most one minute.
update.run();
Sounds like a job for Quartz. You can do this using the following cron expression:
0 * * * * ?
Date d = new Date(System.currentTimeMillis());
Then you can get the minutes by d.getMinutes(). Have a check running in a thread waiting for the value of d.getMinutes() to change.
Finally after some trial and errors I have managed to make it work as I wanted.
But now I would like your advice to make the code more readable and simple it seems a made a lot of unnecessary code to archive what I wanted.
What this basicly do is, if you turn on the server app at a time a schedule task should be running, it will start the task and let it run for the time left from when it should have started otherwise it will be schedule to run at the hour it is supposed to run.
So if the schedule time is 13:00:00 and should run for 120 minutes and you start the app at 13:30 it will run for 90 minutes. If you start it after that time, it will be normally schedule for the next day 13:00:00.
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
long start_time = calendar.getTimeInMillis() - System.currentTimeMillis();
if (start_time < 0)
{
long minutes = (start_time*-1) / (60 * 1000);
if (minutes > 0 && minutes < 120)
{
runTimeLeft = 120 - minutes;
ThreadPoolManager.getInstance().schedule(new Runnable()
{
public void run()
{
myTask();
}
}, 0);
}
else
runTimeLeft = 0;
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, hour+24);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
start_time = calendar.getTimeInMillis() - System.currentTimeMillis();
}
ThreadPoolManager.getInstance().scheduleAtFixedRate(new Runnable()
{
public void run()
{
myTask();
}
}, start_time, 24 * 60 * 60 * 1000);
So my question here now is what could I improve on the above code ?
Instead of using java.util.Timer alone, try using it with TimerTask. There is a good article from IBM on this.
Have a look at this link: http://www.ibm.com/developerworks/java/library/j-schedule.html
The code is also shared and seems to work for trivial routine job.
Use this instead for your first method:
int interval = 24 * 60 * 60 * 1000; // might be long instead of int
ThreadPoolManager.getInstance().scheduleAtFixedRate(new Runnable()
{
public void run()
{
myTask();
}
}, interval, interval);
This will create a simple timer that will call myTask() in 24 hours, and then every 24 hours after.
Your other requirement is a little different, though. If I understand your description correctly, you basically want your app to always execute some task at 12:00 AM if it happens to be up and running. If you don't care about down-to-the-millisecond accuracy for this, you could achieve it very simply by starting a Timer with a one minute period and checking the current system time in each tick - when you hit 12:00 AM run your daily task.
A fancier way would involve interacting with the OS such that it makes callbacks to your application at pre-scheduled times (possibly even starting your app if necessary), but this kind of thing is OS/platform specific (which you didn't specify).
Update: I know nothing about Linux, but it looks like a cron job is what you're looking for. See this question:
Running a scheduled task written in java on a linux server
Below is a sample of the code I was trying, I need to run 1 task in 3 different times for X minutes every day and let's say I have 12,17,20 and it should run for 120 minutes and it is already 12:30:00 so if i open the application it should start the task and it should run for 90 minutes.
What am I doing wrong here and what do I have to change in order to do the above ?
// here I receive my config with the hours I need to run my task
String[] time = Config.SCHEDULE.split(",");
int runTimeLeft = Config.TIMELEFT;
for (String hour : time)
{
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hour));
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
long start = calendar.getTimeInMillis() - System.currentTimeMillis();
ThreadPoolManager.getInstance().scheduleAtFixedRate(new Runnable()
{
public void run()
{
startMyTask();
}
}, start, 24 * 60 * 60 * 1000);
}
It's not exactly a Java problem...
You need to check if current time (in the calendar) minus current recieved time is more than 0 and less than 2 hours, and if so run the task for "2 hours minus this DIFFERENCE", else what you wrote.