I have a custom timer that I'm keeping synced to the system clock. It's working fine for one minute intervals, but I also need it to sync to 36 second intervals (for updating fields when the user wants times displayed in decimal hours). Inside the Runnable I recalculate the adjustment (accurate enough for my needs) for the next minute, but can't find a way to conveniently deal with the different offsets needed for 36 seconds.
EDIT
private static class DecimalTimer extends TimerClass {
final int[] seconds = new int[101];
private boolean keepRunning = true;
private Runnable mRunnable;
#Override
void kill() {
keepRunning = false;
}
#Override
Runnable getRunnable() {
return mRunnable;
}
DecimalTimer() {
final int[] counter = new int[1];
for (int i = 0, j = 0; i < 3600; i += 36, j++) {
seconds[j] = i;
}
mRunnable = new Runnable() {
#Override
public void run() {
if (!keepRunning)
return;
final Calendar c = Calendar.getInstance();
int hourSeconds = c.get(Calendar.MINUTE) * 60 + c.get(Calendar.SECOND);
for (counter[0] = 0; counter[0] < 100; counter[0]++) {
if (seconds[counter[0]] > hourSeconds) {
c.add(Calendar.SECOND, seconds[counter[0]]);
break;
}
}
long adjustedDelay = (c.getTimeInMillis() - System.currentTimeMillis()) % 36000;
for (IntervalTimer listener : sListeners) {
listener.updateTime();
}
sHandler.postDelayed(this, adjustedDelay);
}
};
}
}
This edit fires every 36 seconds, but I need to get it to sync to 36 seconds on the clock (ie: 12:00:00, then 12:00:36 .. 12:01:12 .. 12:01:48)
Overthinking things as usual, this is what I came up with. It's accurate enough for what I need, but if anyone has an improvement for accuracy (It's a little off when it executes with 900ms or more) it'd be appreciated.
DecimalTimer() {
mRunnable = new Runnable() {
#Override
public void run() {
if (!keepRunning)
return;
final Calendar c = Calendar.getInstance();
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
do {
c.add(Calendar.SECOND, 36);
} while (c.getTimeInMillis() < System.currentTimeMillis());
long adjustedDelay = (c.getTimeInMillis() - System.currentTimeMillis()) % 36000;
for (IntervalTimer listener : sListeners) {
listener.updateTime();
}
sHandler.postDelayed(this, adjustedDelay);
}
};
}
Related
*** warning: Java real-time priorities >=11 not usable, using priority 10 (cause: Operation not permitted)
currently trying out a project that come out with this error message.
using Xfce environment in Vmware, eclipse ide and jamaica vm
what is actually wrong with this? The error state that the java real-time priorities is bigger than 11 when the system priority is 10, how can I set the priority higher?
my code
package realtime;
import javax.realtime.*;
class seconds extends RealtimeThread{
int secs = 0;
int mins = 0;
int hours=0;
public seconds(SchedulingParameters sched, ReleaseParameters rel)
{
super(sched,rel);
}
public void run() {
while(true) {
secs++;
System.out.println("seconds" + secs);
if(secs>58) {
mins ++;
secs = 0;
}
boolean ok = waitForNextPeriod();
}
}
}
class minutes extends RealtimeThread{
private minutes min = null;
private seconds sec = null;
int mins = 0;
int hours = 0;
public minutes(SchedulingParameters sched, ReleaseParameters rel)
{
super(sched,rel);
}
public void run() {
while(true) {
mins++;
System.out.println("minutes" + mins);
if(mins>58) {
hours ++;
mins = 0;
}
boolean ok = waitForNextPeriod();
}
}
}
class hours extends RealtimeThread{
private minutes min = null;
private seconds sec = null;
private hours hour=null;
int mins = 0;
int hours = 0;
int day =0;
public hours(SchedulingParameters sched, ReleaseParameters rel)
{
super(sched,rel);
}
public void run() {
while(true) {
mins++;
System.out.println("hours" + hours);
if(hours>24) {
day ++;
hours= 0;
}
boolean ok = waitForNextPeriod();
}
}
}
public class Q1 {
private minutes min = null;
private seconds sec = null;
private hours hour = null;
Q1(){
PriorityParameters hoursched = new PriorityParameters(PriorityScheduler.instance().getMaxPriority());
ReleaseParameters hoursrel = new PeriodicParameters(new RelativeTime(59*59*1000,1000));
PriorityParameters minsched = new PriorityParameters(PriorityScheduler.instance().getMinPriority());
ReleaseParameters minrel = new PeriodicParameters(new RelativeTime(59000,1000));
PriorityParameters secsched = new PriorityParameters(PriorityScheduler.instance().getMaxPriority());
ReleaseParameters secrel = new PeriodicParameters(new RelativeTime(1000,0));
hour = new hours(hoursched,hoursrel);
min = new minutes(minsched, minrel);
sec = new seconds(secsched, secrel);
hour.start();
min.start();
sec.start();
}
public static void main(String[] args) {
Q1 t = new Q1();
}
}
This is an FAQ in the JamaicaVM Manual:
The answer says:
"The creation of a thread with real-time priority was not permitted by the operating system. Instead JamaicaVM created a thread with normal priority. This means that real-time scheduling is not available, and that the application will likely not work properly.
On off-the-shelf Linux systems, use of real-time priorities requires super-user privileges. That is, starting the application with
sudo will resolve the issue. Alternatively, the priority limits for particular users or groups may be changed by editing /etc/security/limits.conf and setting rtprio to the maximum native priority used. For the default priority map used by JamaicaVM on Linux, setting the rtprio
limit to 80 is sufficient."
I'm trying to create a clock programm with customizable options but since I'm a beginner I'm running into some problems. I tried using the DigitalClock project but there's too many things in it for me right now
I looked into Timer and ScheduledExecuterService but I don't know how to use and where to place them.
I also tried to set a color to the background but the error was that it could be over ran.
How can I repeat the process in milliseconds, add a background and make the code lighter ?
public Clock() {
initComponents();
Calendar cal = new GregorianCalendar();
int second = cal.get(Calendar.SECOND);
int minute = cal.get(Calendar.MINUTE);
int hour = cal.get(Calendar.HOUR_OF_DAY);
/////////////////////////////////////////////////////////////
if (second < 10){
time.setText(" "+hour+": "+minute+":0"+second+"");
}
else if (minute < 10){
time.setText(" "+hour+":0"+minute+": "+second+"");
}
else if (hour < 10){
time.setText("0"+hour+": "+minute+": "+second+"");
}
else if (hour < 10 & minute < 10){
time.setText("0"+hour+":0 "+minute+": "+second+"");
}
else if (minute < 10 & second < 10){
time.setText(" "+hour+":0"+minute+":0"+second+"");
}
else if (hour < 10 & minute < 10 & second < 10){
time.setText("0"+hour+":0"+minute+":0"+second+"");
}
else {
time.setText(hour + " : " + minute + " : " + second+"");
}
////////////////////////////////////////////////////////////////
}
If you want to make it simple then you can simple do the following:
public static void main (String[] args) throws Exception
{
final SimpleDateFormat sf = new SimpleDateFormat("HH:mm:ss:SSS");
while(true) {
System.out.println(sf.format(new Date()));
Thread.sleep(1);
}
}
But this might miss a millisecond entry in between. For example, it might go directly to 310 after 308 and miss 309 in between. But since we are talking about 1/1000th of a second, in real life it is very unlikely to be noticed.
Your code will reduce to something like following:
public Clock() {
public static void main (String[] args) throws Exception {
initComponents();
final SimpleDateFormat sf = new SimpleDateFormat("HH:mm:ss:SSS");
while(true) {
time.setText = sf.format(new Date());
Thread.sleep(1);
}
}
}
final SimpleDateFormat sf = new SimpleDateFormat("HH:mm:ss:SSS");
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
System.out.println(sf.format(new Date()));
}
}, 0 , 1000000);
Will repeat in 1 ms.
I have a timer with a delay of 5 seconds. I am trying to change the label named lblTimer after a second passes to act as a countdown. I am having issues with it as currently it only works at 5 seconds. Do you have any suggestionsuggestions?
protected void Addition() {
//addition function
final int delay = 5000; //milliseconds
ActionListener taskPerformer = new ActionListener() {
#SuppressWarnings("unused")
public void actionPerformed(ActionEvent evt) {
//...Perform a task...
frame.getContentPane().setBackground(Color.red);
}
};
new Timer(delay, taskPerformer).start();
Random RandomNumber = new Random();
int number1 = RandomNumber.nextInt(12);
int number2 = RandomNumber.nextInt(12);
int number3 = RandomNumber.nextInt(12);
lblAnswer.setText("");
lblFirstNumber.setText(""+ number1);
lblfunction1.setText("+");
lblsecondNumber.setText(""+number2);
lblfunction2.setText("+");
lblthirdnumber.setText(""+number3);
lblequals.setText("=");
answer = number1+number2+number3;
if(delay <= 1000){
lblTimer.setText("1");
}
else if(delay == 2000){
lblTimer.setText("2");
}
else if(delay == 3000){
lblTimer.setText("3");
}
else if(delay == 4000){
lblTimer.setText("4");
}
else if (delay == 5000){
lblTimer.setText("5");
}
}
The answer to your question, that I assume is "why does this not work?", is that at no point do you recheck the elapsed time. The variable delay is always set at 5000, and never updated, also.
The stupid-ass solution:
lblTimer.setText("5");
Thread.sleep(1000)
lblTimer.setText("4");
Thread.sleep(1000)
lblTimer.setText("3");
Thread.sleep(1000)
lblTimer.setText("2");
Thread.sleep(1000)
lblTimer.setText("1");
Thread.sleep(1000)
lblTimer.setText("0");
Don't really do this, unless you need to satisfy your sick fetishes.
The four-liner
The same as above. Don't do this.
for (int i = secondsToWait; i >= 0; i--) {
lblTimer.setText(i + "");
Thread.sleep(1000);
}
The acceptable solution:
Use a Timer to schedule a task to be executed after a given period of time. You can use timers to also fire the same task multiple times at a given interval.
Timer timer = new Timer();
int secondsToWait = 5;
TimerTask task = new TimerTask() {
#Override
public void run() {
secondsToWait--;
lblTimer.setText(secondsToWait + "");
if (secondsToWait == 0) {
timer.cancel();
timer.purge();
}
}
};
lblTimer.setText(secondsToWait + "");
timer.scheduleAtFixedRate(task, 1000, 1000);
The best solution:
Instead of a timer, use a ScheduledExecutorService. This is better because of the way ScheduledExecutorService works with threads as opposed to Timer. Google it.
ScheduledExecutorService exec = Executors.newScheduledThreadPool(1);
int secondsToWait = 5;
Runnable task = new Runnable() {
#Override
public void run() {
secondsToWait--;
lblTimer.setText(secondsToWait + "");
if (secondsToWait == 0) {
exec.shutdown();
}
}
};
lblTimer.setText(secondsToWait + "");
exec.scheduleAtFixedRate(task, 1, 1, TimeUnit.SECONDS);
EDIT: As Stefan pointed out, for swing GUI applications a swing Timer would be the best pick.
It should look something like this:
1) create Timer
2) create TimerTask and implement run method (updating your count variable and check if counter is zero. if it is zero, stop the timer)
3) schedule the task to run every second
int count = [INITVALUE];
...
public void startMethod() {
final Timer timer = new Timer();
timer.shedule(new TimerTask() {
#Override
public void run() {
count--;
lblTimer.setText(count+"");
if (count == 0) {
timer.cancel();
timer.purge();
}
}
},1000);
}
Thumbs Up #Olavi Mustanoja your answer revealed an option I have never tried before now.
As he lastly suggested on his edit the javax.swing.Timer comes in very handy if you're work with GUI.
import javax.swing.Timer;
private int secondsToWait = 5000; //Time in milliseconds
private Timer timer;
....
//The following section should be inside a method member
timer = new Timer(secondsToWait, e -> {
if(secondsToWait == 0)
timer.stop();//Stop if secondsToWait is already zero
lblTimer.setText((secondsToWait/1000) + ""); //Update the label with the current sec
timer.setDelay(secondsToWait);
secondsToWait -= 1000; //Reduce time by 1sec each time
});
timer.start();
...
I am wondering the best way to keep a timer going in the background while a game is played.
I am programming a version of the HiLo game (in Java), which gives a user a certain amount of time to determine a number. If a guess is not correct, the game will tell the user whether the name is too high or too low.
I'm keeping track of time using System.currentTimeMillis() and seeing how much time has elapsed. This seems to work well, and so far I have been checking to see how much time has elapsed each time a new number is entered. For example, currently the app output looks like this:
Welcome to HiLo!
You have 10 seconds to guess a number I'm thinking of between 1 and 100.
> 67
Too high.
> 29
Too low.
Half of your time is gone! Only 5 seconds remains!
> 37
Too high.
> 33
Oops! Time is up - try again.
As you can see, currently, it can only check when I enter a new number how much time is passed.
I have tried creating a thread to start with a timer, however, when I start it, it keeps counting until the time is exhausted, without going on to the thread.run(int guess) which will be run when there is a new guess. I want to be able to still make guesses while the counter runs. Here is my attempt at a new implementation for thread.start():
public void start(int time_sent) throws InterruptedException {
time = time_sent;
startTime = (System.currentTimeMillis() / 1000);
while (1==1) {
long elapsed = ((System.currentTimeMillis() / 1000) - (startTime));
if (elapsed >= (time)) {
System.out.println("Oops! Time is up - try again.");
System.exit(0);
}
else if (elapsed >= (time/2) && !halfWarning) {
System.out.println("Half of your time is gone! Only " + (time/2) + " seconds remains!");
halfWarning = true;
}
}
}
How can I continue running this counter in the background?
This is one more approach:
public void game() {
Scanner scanner = new Scanner(System.in);
int time = 10; // sec
message("You have " + time + " seconds to guess...");
new Thread(new Background(System.currentTimeMillis() / 1000, time)).start();
while (true) {
String s = scanner.next();
if (s.equals("55")) {
message("You win");
System.exit(0);
} else {
message("try again...");
}
}
}
private void message(String str) {
System.out.println(str);
System.out.print("> "); // monit
}
You start 1 thread with behavior implemented in Background class. Next you enter while loop to capture user inputs. The Background thread works in background...
private class Background implements Runnable {
private long startTime;
private long time;
private boolean halfWarning;
private Background(long startTime, long time) {
this.startTime = startTime;
this.time = time;
}
#Override
public void run() {
while (true) {
long now = System.currentTimeMillis() / 1000;
long elapsed = now - startTime;
if (elapsed >= (time / 2) && !halfWarning) {
message("\n Half of your time is gone! Only " + (time / 2) + " seconds remains!");
halfWarning = true;
}
if (elapsed >= time) {
message("\n Oops! Time is up - try again.");
System.exit(0);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
//ignore
}
}
}
}
Use a ScheduledExecutorService to execute concurrent actions in the future:
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture<?> half = ses.schedule(new Runnable() {
#Override
public void run() {
System.out.println("Half of your time is gone!");
}
}, time / 2, TimeUnit.SECONDS);
ScheduledFuture<?> full = ses.schedule(new Runnable() {
#Override
public void run() {
System.out.println("Oops! Time is up - try again.");
// System.exit(0) ?
}
}, time, TimeUnit.SECONDS);
// check
if (input == toGuess) {
half.cancel();
full.cancel();
}
You could have a Timer thread that prints out these messages and shuts down the listening program.
It might inspire you :
public static class Game extends TimerTask {
private long start;
private long end;
public Game(long end) {
super();
this.start = System.currentTimeMillis();
this.end = end;
}
#Override
public void run() {
while (System.currentTimeMillis() - start < end)
System.out.println(System.currentTimeMillis());
}
}
public static void main(String[] args) {
TimerTask task = new Game(10000);
Timer timer = new Timer();
timer.schedule(task,0);
}
I am trying to run a certain task every Friday in a week at any time. So I decided to use ScheduledExecutorService for this but so far I have seen examples which shows how to run task every few minutes.
Below is my code which I adopted to run every day at 5 AM in the morning. How do I use this to run task every Friday in a week at any time?
public static void main(String[] args) {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);
Date aDate = new Date();
Calendar with = Calendar.getInstance();
with.setTime(aDate);
int hour = with.get(Calendar.HOUR_OF_DAY);
int intDelayInHour = hour < 5 ? 5 - hour : 24 - (hour - 5);
System.out.println("Current Hour: " + hour);
System.out.println("Comuted Delay for next 5 AM: " + intDelayInHour);
scheduler.scheduleAtFixedRate(new Runnable() {
public void run() {
try {
getDataFromDatabase();
} catch (Exception ex) {
ex.printStackTrace(); // or loggger would be better
}
}
}, intDelayInHour, 24, TimeUnit.HOURS);
}
protected static void getDataFromDatabase() {
// TODO Auto-generated method stub
}
Can anyone provide an example how would I do this?
You would have to check what day it is today.
Then set the delay to the next Friday (lets say it is Tuesday, then set a 3 day delay, or use hours if you want to set it at a different time).
And then use a 7 day period (or equivallent in hours).
EDIT:
As requested you can do something like.
Map<Integer, Integer> dayToDelay = new HashMap<Integer, Integer>()
dayToDelay.put(Calendar.FRIDAY, 0);
dayToDelay.put(Calendar.SATURDAY, 6);
dayToDelay.put(Calendar.SUNDAY, 5);
dayToDelay.put(Calendar.MONDAY, 4);
dayToDelay.put(Calendar.TUESDAY, 3);
dayToDelay.put(Calendar.WEDNESDAY, 2);
dayToDelay.put(Calendar.THURSDAY, 1);
int dayOfWeek = with.get(DAY_OF_WEEK);
int delayInDays = dayToDelay.get(dayOfWeek);
scheduler.scheduleAtFixedRate(new Runnable() {
public void run() {
try {
getDataFromDatabase();
} catch (Exception ex) {
ex.printStackTrace(); // or loggger would be better
}
}
}, delayInDays, 7, TimeUnit.DAYS);
That should run the task every Friday at the time this is executed.
TO RUN PROGRAM EVERY MONDAY AT 11 AM
public static void main(String args[]){
new WeeklyReportService();
}
WeeklyReportService.java
public class WeeklyReportService{
public WeeklyReportService(){
this.startScheduler();
}
private void startScheduler(){
Calendar with = Calendar.getInstance();
Map<Integer, Integer> dayToDelay = new HashMap<Integer, Integer>();
dayToDelay.put(Calendar.FRIDAY, 2);
dayToDelay.put(Calendar.SATURDAY, 1);
dayToDelay.put(Calendar.SUNDAY, 0);
dayToDelay.put(Calendar.MONDAY, 6);
dayToDelay.put(Calendar.TUESDAY, 5);
dayToDelay.put(Calendar.WEDNESDAY, 4);
dayToDelay.put(Calendar.THURSDAY, 3);
int dayOfWeek = with.get(Calendar.DAY_OF_WEEK);
int hour = with.get(Calendar.HOUR_OF_DAY);
int delayInDays = dayToDelay.get(dayOfWeek);
int delayInHours = 0;
if(delayInDays == 6 && hour<11){
delayInHours = 11 - hour;
}else{
delayInHours = delayInDays*24+((24-hour)+11);
}
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(new WeeklyTask(), delayInHours,
179, TimeUnit.HOURS);
}
WeeklyTask.java
Public class WeeklyTask implements Runnable {
#Override
public void run() {
System.out.println("start of weekly report");
/*Your Program to run*/
System.out.println("end of weekly report");
}
}
Hope this helps! You can apply same to any day. In your case, for Friday 11 AM it will be
dayToDelay.put(Calendar.FRIDAY, 6);
dayToDelay.put(Calendar.SATURDAY, 5);
dayToDelay.put(Calendar.SUNDAY, 4);
dayToDelay.put(Calendar.MONDAY, 3);
dayToDelay.put(Calendar.TUESDAY, 2);
dayToDelay.put(Calendar.WEDNESDAY, 1);
dayToDelay.put(Calendar.THURSDAY, 0);