So I wanted to try out something for a bit with the Timer and TimerTask classes.
I was able to get a line of code to execute after 30 seconds elapsed.
What I've been trying to do now is to get this line of code to execute for 5 minuets.
This is what I originally tried
public static void main(String[] args)
{
for ( int i = 0; i <= 10; i ++ )
{
Timer timer = new Timer();
timer.schedule( new TimerTask()
{
public void run()
{
System.out.println("30 Seconds Later");
}
}, 30000
);
}
}
I used the number 10 in the for loop to see if the timer.schedule would wait for another 30 seconds during the next iteration of the loop.
Any idea how I should go about this? I tried using the schedule method with a parameter passed in for period, but that only made it re-execute and it never stopped.
Java has provided a rich set of APIs in java.util.concurrent package to achieve such tasks. One of these APIs is ScheduledExecutorService. For example consider the code given below: This code will execute the Runnable task after every 30 seconds for upto 5 minutes:
import java.util.concurrent.*;
class Scheduler
{
private final ScheduledExecutorService service;
private final long period = 30;//Repeat interval
public Scheduler()
{
service = Executors.newScheduledThreadPool(1);
}
public void startScheduler(Runnable runnable)
{
final ScheduledFuture<?> handler = service.scheduleAtFixedRate(runnable,0,period,TimeUnit.SECONDS);//Will cause the task to execute after every 30 seconds
Runnable cancel = new Runnable()
{
#Override
public void run()
{
handler.cancel(true);
System.out.println("5 minutes over...Task is cancelled : "+handler.isCancelled());
}
};
service.schedule(cancel,5,TimeUnit.MINUTES);//Cancels the task after 5 minutes
}
public static void main(String st[])
{
Runnable task = new Runnable()//The task that you want to run
{
#Override
public void run()
{
System.out.println("I am a task");
}
};
Scheduler sc = new Scheduler();
sc.startScheduler(task);
}
}
The issue you're running into is that the scheduled Timer runs on a different thread - that is, the next iteration of your for loop starts running immediately after scheduling, not 30 seconds later. It looks like your code starts ten timers all at once, which means they should all print (roughly) 30 seconds later, all at once.
You were on the right track when you tried using the recurring version of schedule (with the third parameter). As you noted, this isn't quite what you want because it runs indefinitely. However, Timer does have a cancel method to prevent subsequent executions.
So, you should try something like:
final Timer timer = new Timer();
// Note that timer has been declared final, to allow use in anon. class below
timer.schedule( new TimerTask()
{
private int i = 10;
public void run()
{
System.out.println("30 Seconds Later");
if (--i < 1) timer.cancel(); // Count down ten times, then cancel
}
}, 30000, 30000 //Note the second argument for repetition
);
here's a workaround I'm ashamed of presenting:
package test;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class FiveMinutes {
private static int count = 0;
// main method just to add example
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
System.out.println("Count is: " + count);
if (count == 1) {
System.err.println("... quitting");
System.exit(0);
}
count++;
}
},
// starting now
new Date(),
// 5 minutes
300000l
);
}
}
Also please note that the application might not run exactly 5 minutes - see documentation for TimerTask.
Your solution is pretty close to working, you just have to multiply the delay by the counter (in your case, i):
public static void main(String[] args)
{
for (int i = 1; i <= 10; i++) // start i at 1 for initial delay
{
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run()
{
System.out.println("30 Seconds Later");
}
}, 30000 * i); // 5 second intervals
}
}
I don't know if this solution has problems with the garbage collector or not, but I throw it in here anyways. Maybe someone clears that out, and I learn something as well. Basically a timer sets a new timer if there is time left, and it should stop after 5 minutes.
Main.java:
public class Main {
public static void main(String[] args) {
MyTimer myTimer = new MyTimer(300000,30000);
myTimer.startTimer();
}
}
MyTimer.java:
import java.util.Timer;
import java.util.TimerTask;
public class MyTimer {
private int totalRunningTime;
private int currentTime = 0;
private int intervalTime;
private Timer timer = new Timer();
public MyTimer(int totalRunningTime, int intervalTime) {
this.totalRunningTime = totalRunningTime;
this.intervalTime = intervalTime;
}
public void startTimer() {
startTimer(intervalTime);
}
private void startTimer(int time) {
timer.schedule(new TimerTask() {
public void run() {
if (currentTime <= totalRunningTime - intervalTime) {
printTimeSinceLast(intervalTime / 1000);
currentTime += intervalTime;
startTimer(intervalTime);
} else if (currentTime < totalRunningTime) {
int newRestIntervalTime = totalRunningTime - currentTime;
printTimeSinceLast(newRestIntervalTime / 1000);
currentTime += newRestIntervalTime;
startTimer(newRestIntervalTime);
}
}
}, time);
}
private void printTimeSinceLast(int timeSinceLast) {
System.out.println(timeSinceLast + " seconds later.");
}
}
Related
I have the following code whose purpose is to increment a prometheus counter if periodic calls stop coming to messageReceived():
...
private static final int tenMinutes = 10 * 60 * 1000;
private Timer timer = new Timer();
private boolean newTimer = false;
...
public void messageReceived() {
timer.cancel();
timer = new Timer();
newTimer = true;
TimerTask action = new TimerTask() {
public void run() {
if (!newTimer)
counter.increment();
else
newTimer = false;
}
};
timer.schedule(action, tenMinutes, tenMinutes);
}
...
The goal is to set a timer that will only fire an action if a new event is not received. Every time messageReceived() is called before ten minutes have passed, the timer should be cancelled so it will not fire.
What I am seeing happen is pretty much exactly every ten minutes the action fires, even though messageReceived is called more than once per minute.
MessageReceived is called from a service so its not called on the same thread every time, but messageReceived is inside a singleton. I am not sure, but I would think that if multithreading was the problem, I would see many firings of "action" and not just one every 10 minutes.
I think you do have a multi-threading problem, just like SnowmanXL said. Here is a simple MCVE reproducing the problem:
import java.text.SimpleDateFormat;
import java.util.*;
class MiscellaneousMonitor {
private static SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
private boolean isRunning;
private Counter counter;
private static final int tenMinutes = /*10 * 60 **/ 1000;
private Timer timer = new Timer();
private boolean newTimer = false;
static class Counter {
private int count = 0;
public /*synchronized*/ void increment() {
count++;
}
}
public /*synchronized*/ void start() {
counter = new Counter();
isRunning = true;
}
public /*synchronized*/ void messageReceived() {
timer.cancel();
timer = new Timer();
newTimer = true;
TimerTask action = new TimerTask() {
public void run() {
System.out.println(dateFormat.format(new Date()) + " Timer task running: " + this);
if (!newTimer)
counter.increment();
else
newTimer = false;
}
};
timer.schedule(action, tenMinutes, tenMinutes);
}
public /*synchronized*/ void stop() {
timer.cancel();
isRunning = false;
}
public /*synchronized*/ boolean isRunning() {
return isRunning;
}
public static void main(String[] args) throws InterruptedException {
MiscellaneousMonitor monitor = new MiscellaneousMonitor();
monitor.start();
Queue<Thread> threads = new LinkedList<>();
for (int t = 0; t < 10; t++) {
Thread thread = new Thread(() -> {
for (int i = 0; i < 10; i++) {
try { Thread.sleep(150); } catch (InterruptedException e) { e.printStackTrace(); }
monitor.messageReceived();
}
try { Thread.sleep(1500); } catch (InterruptedException e) { e.printStackTrace(); }
});
thread.start();
threads.add(thread);
}
while (!threads.isEmpty()) {
threads.poll().join();
}
monitor.stop();
}
}
The console log will look something like this:
Exception in thread "Thread-4" java.lang.IllegalStateException: Timer already cancelled.
at java.base/java.util.Timer.sched(Timer.java:398)
at java.base/java.util.Timer.schedule(Timer.java:249)
at MiscellaneousMonitor.messageReceived(scratch_3.java:39)
at MiscellaneousMonitor.lambda$main$0(scratch_3.java:59)
at java.base/java.lang.Thread.run(Thread.java:832)
09:25:58.147 Timer task running: MiscellaneousMonitor$1#1ce7fd7d
09:25:58.142 Timer task running: MiscellaneousMonitor$1#7ba42a49
09:25:58.147 Timer task running: MiscellaneousMonitor$1#493cb0eb
09:25:58.147 Timer task running: MiscellaneousMonitor$1#6f9a3afe
09:25:58.148 Timer task running: MiscellaneousMonitor$1#1d86f308
Exception in thread "Thread-9" java.lang.IllegalStateException: Timer already cancelled.
at java.base/java.util.Timer.sched(Timer.java:398)
at java.base/java.util.Timer.schedule(Timer.java:249)
at MiscellaneousMonitor.messageReceived(scratch_3.java:39)
at MiscellaneousMonitor.lambda$main$0(scratch_3.java:59)
at java.base/java.lang.Thread.run(Thread.java:832)
09:25:58.445 Timer task running: MiscellaneousMonitor$1#53c65632
09:25:58.445 Timer task running: MiscellaneousMonitor$1#6ce24daa
09:25:58.445 Timer task running: MiscellaneousMonitor$1#784b861f
09:25:58.447 Timer task running: MiscellaneousMonitor$1#783528c9
09:25:58.447 Timer task running: MiscellaneousMonitor$1#2cc4944f
09:25:58.597 Timer task running: MiscellaneousMonitor$1#711e91d9
09:25:58.597 Timer task running: MiscellaneousMonitor$1#19ddcb88
09:25:58.597 Timer task running: MiscellaneousMonitor$1#5fbdc1a8
(...)
Sometimes you see the execeptions, sometimes not, depending on the timing when you run the program. But even if you do not see any exceptions, multiple timer tasks - MiscellaneousMonitor$1 is the internal name of the anonymous TimerTask instance - will log forever and never be cancelled, which is why the program continues to run forever until you kill it, despite you calling join() on all running tasks. But there are still rogue TimerTasks.
Now if you uncomment all synchronized keywords where I put them in the code, your console log will change to the expected
09:31:44.880 Timer task running: MiscellaneousMonitor$1#4f963263
and the program will terminate.
P.S.: You maybe could synchronise on smaller sections of code instead of on whole methods, I did not analyse that. I just showed you the basic problem of thread unsafety with your singleton which is accessed by multiple other threads, like you said.
I've been looking for a way to create a timer that counts up in the format of mm:ss:SS and cannot for the life of me find a way of doing it. I had a timer running through a Handler and a Runnable but the timing was off and it took around 2.5 seconds to do a "second". I'll also need this timer be able to countdown too!
Can anyone give me any resources or code snippets to research on this as it is a big part of the app I'm coding.
Here's a bit of the code that I was using
private Handler handler = new Handler();
private Runnable runnable = new Runnable() {
#Override
public void run() {
/* do what you need to do */
testMethod();
/* and here comes the "trick" */
handler.postDelayed(this, 10);
}
};
public void testMethod()
{
// Log.d("Testing", "Test");
final TextView timeLabel = (TextView)findViewById(R.id.timeString);
count++;
seconds = (int)(count / 100);
final String str = ""+count;
runOnUiThread(new Runnable() {
public void run() {
timeLabel.setText("" + seconds);
// Log.d("Time", "" + count);
}
});
}
Ta!
Make small custom class by extending CountDownTimer class and then add integer or long type and then increment it, since each tick is 1 second (integer) in this case
public class TimeCounter extends CountDownTimer {
// this is my seconds up counter
int countUpTimer;
public TimeCounter(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
countUpTimer=0;
}
#Override
public void onTick(long l) {
//since each tick interval is one second
// just add 1 to this each time
myTextView.setText("Seconds:"+countUpTimer);
countUpTimer = countUpTimer+1;
}
#Override
public void onFinish() {
//reset counter to 0 if you want
countUpTimer=0;
}
}
TimeCounter timer = new TimeCounter(whenToStopInSeconds*1000, 1000);
This should get you started, in your case use long instead integer
countUpTimer = countUpTimer+1000 countUpTimer type and do time parsing as suits you
Rather than using the Handler, I'd recommend using the java.util.Timer and the java.util.TimerTask APIs. Use the Timer's void scheduleAtFixedRate() method which basically executes tasks after a fixed interval of time. The Handler's method most likely uses a fixed-delay execution.
Timer's Documentation
TimerTask's Documentation
I actually have a video streaming application and I want to show the time for how much the two people have chatted with eachother. I have used Timer and TimerTask of java.util class but it gives error as "Not on FX application thread" which means I cant setText to a java fx component using swing thread. This is what I have tried so far:-
int timerx=0 //global variable
private void timer(){
/*SHOWING TIME PASSED*/
int x=0;
Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
System.out.println("working");
setTime();
}
};
timer.schedule(timerTask, 50, 50);
}
And updating the javafx Label as:-
private void setTime(){
timerx = timerx +1;
Platform.runLater(new Runnable(){
public void run(){
time.setText(String.valueOf((timerx)));
System.out.println(time.getText());
}
});
}
I think the main problem is javafx component not being able to update and be accessed from swing thread. I would be glad to get any kind of help.
Thank you
You can use something like this:
long timeStart = System.currentTimeMillis();
when the chat start and get how long two guys chatted with something like this:
long timePassed = System.currentTimeMillis() - timeStart;
This will get you how many millisecond have passed. If you want to get second divide it by 1000. Oh and if you want it on thread, just create a thread for this thingy..
ok thank you all for your answers. I solved my problem by running a thread and using algorithm that will show the time in 00:00:00 format which I wanted to make. Here is the code
private void startTime(){
if(timerStats==false)
{
timerStats = true;
timer = new Timer();
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
System.out.println("working" + x);
timersec ++;
Platform.runLater(new Runnable(){
public void run(){
if (timersec == 60)
{
timersec = 0;
timermin++;
}
if (timermin == 60)
{
timermin = 0;
timerhr++;
}
String seconds = Integer.toString(timersec);
String minutes = Integer.toString(timermin);
String hours = Integer.toString(timerhr);
if (timersec <= 9)
{
seconds = "0" + Integer.toString(timersec);
}
if (timermin <= 9)
{
minutes = "0" + Integer.toString(timermin);
}
if (timerhr <= 9)
{
hours = "0" + Integer.toString(timerhr);
}
time.setText(hours + ":" + minutes +":"+ seconds);
System.out.println(time.getText());
}
});
}
};
timer.schedule(timerTask, 50, 50); //lastone is time, milli second
}
}
Thank you
Basically I am making a text based "game" (Not so much a game, more of a way to improve basic java skills and logic). However, as part of it I wish to have a timer. It would count down on the time I wish from the variable to 0. Now, I have seen a few ways to do this with a gui, however, is there a way to do this without a gui/jframe etc.
So, what I am wondering is. Can you make a count down from x to 0 without using a gui/jframe. If so, how would you go about this?
Thanks, once I have some ideas will edit with progress.
Edit
// Start timer
Runnable r = new TimerEg(gameLength);
new Thread(r).start();
Above is how I am calling the thread/timer
public static void main(int count) {
If I then have this in the TimerEg class, the timer complies. However, when compiling the main in the other thread I get.
Now, am I completely miss-understanding threads and how this would work? Or is there something I am missing?
Error:
constructor TimerEg in class TimerEg cannot be applied to given types;
required: no arguments; found int; reason: actual and formal arguments differ in length
Found on line Runnable r = new TimerEg(gameLength);
Same as with a GUI, you'd use a Timer, but here instead of using a Swing Timer, you'd use a java.util.Timer. Have a look at the Timer API for the details. Also have a look at the TimerTask API since you would use this in conjunction with your Timer.
For example:
import java.util.Timer;
import java.util.TimerTask;
public class TimerEg {
private static TimerTask myTask = null;
public static void main(String[] args) {
Timer timer = new Timer("My Timer", false);
int count = 10;
myTask = new MyTimerTask(count, new Runnable() {
public void run() {
System.exit(0);
}
});
long delay = 1000L;
timer.scheduleAtFixedRate(myTask, delay, delay);
}
}
class MyTimerTask extends TimerTask {
private int count;
private Runnable doWhenDone;
public MyTimerTask(int count, Runnable doWhenDone) {
this.count = count;
this.doWhenDone = doWhenDone;
}
#Override
public void run() {
count--;
System.out.println("Count is: " + count);
if (count == 0) {
cancel();
doWhenDone.run();
}
}
}
You could write your own countdown timer, as simply as:
public class CountDown {
//Counts down from x to 0 in approximately
//(little more than) s * x seconds.
static void countDown(int x, int s) {
while (x > 0 ) {
System.out.println("x = " + x);
try {
Thread.sleep(s*1000);
} catch (Exception e) {}
x--;
}
}
public static void main(String[] args) {
countDown(5, 1);
}
}
Or you could use Java Timer API
It is simple to countdown with java..
int minute=10,second=60; // 10 min countdown
int delay = 1000; //milliseconds
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
second--;
// do something with second and minute. put them where you want.
if (second==0) {
second=59;
minute--;
if (minute<0) {
minute=9;
}
}
}
};
new Timer(delay, taskPerformer).start();
Hi m using the following timer task,and i want to increase the time of this task when a certain condition occurs
Timer timer2=new Timer();
timer2.schedule(new TimerTask(){
public void run(){
//whatevr
}
}, 4000);
examlpe
if(mycondition)
{
increase time????
}
how can i do that
Extract the TimerTask in an inner or standalone class. Cancel currently running timer task and schedule a new instance with increased time period.
You can't. You'll have to schedule a new task with the incremented period. And if the previous task has become obsolete, make sure that you cancel() it.
For future reference, I recommend you utilize the Executors framework.
Submit another one task from run() if necessary:
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class TimerTaskTest {
private static class MyTimerTask extends TimerTask {
private final Timer timer;
private boolean fire;
private MyTimerTask(Timer timer) {
this(timer, false);
}
private MyTimerTask(Timer timer, boolean fire) {
this.timer = timer;
this.fire = fire;
}
#Override
public void run() {
if (!fire) {
System.out.println(new Date() + " - steady...");
timer.schedule(new MyTimerTask(timer, true), 2000);
} else {
System.out.println(new Date() + " - go!");
}
}
}
public static void main(String args[]) {
Timer timer = new Timer(true);
MyTimerTask timerTask = new MyTimerTask(timer);
System.out.println(new Date() + " - ready...");
timer.schedule(timerTask, 4000);
try {
Thread.sleep(7000);
} catch (Exception ignore) {
}
}
}