I develop a simple application and I use timer, but if I run the timer several times the timer drops this exception: Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Timer already cancelled.
Here is my code:
public class Main {
...
private static void createAndShowUI() {
...
//a listener of a radio button
ActionListener on_action = new ActionListener() {
public void actionPerformed(ActionEvent e) {
Timer.timer.schedule(Timer.task,0,2000); //I call the timer here
}
};
...
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
//and the class of timer:
public class Timer {
public static java.util.Timer timer = new java.util.Timer();
public static java.util.TimerTask task = new java.util.TimerTask() {
public void run() {
//some tasks
}
};
}
My question is that where I use the thread? Thanks!
The problem is not using the Event-Queue thread, it is that you are re-using a cancelled Timer.
I'm guessing you are using the Timer to do some animation or something in response to a button push (as you schedule things at a fixed rate). I'm guessing also that in code you don't show us, the timer gets cancelled by a separate event. If you ever call Timer.cancel() can you show us that code?
From the exception what is happening is that you are trying to use the same Timer that you have already cancelled. Once a Timer has been cancelled, it can't be used again.
Two suggestions - use a different Timer every time. Also, if you are doing things for UI purposes, you might want to consider using a Swing timer instead.
As far as the Thread goes, all GUI events happen on the AWT Thread, but I repeat, this is almost certainly not the problem. Read this for more details.
A timer goes into cancelled state if either the cancel() method has been invoked or the if the timer task has terminated unexpectedly:
If the timer's task execution thread terminates unexpectedly, for example, because its stop method is invoked, any further attempt to schedule a task on the timer will result in an IllegalStateException, as if the timer's cancel method had been invoked.
So in your case, it may not be a problem of where you put/call/use your time, but more a problem of what you're actually doing with your timer.
Here you have your thread:
Corresponding to each Timer object is a single background thread that is used to execute all of the timer's tasks, sequentially
so if you try to access your GUI from the Timer task you should put it into the EventQueue thread.
And look here
If the timer's task execution thread terminates unexpectedly, for example, because its stop method is invoked, any further attempt to schedule a task on the timer will result in an IllegalStateException, as if the timer's cancel method had been invoked.
Do you let the Timer schedule any more tasks after it has been cancelled?
Related
In essence, I have an onGuildMessageReceived method that listens for a command alarm with which a user can set a countdown to notify him with a message. They type a time amount and eventual alarm message that comes with the ping they will get after that time.
My question is, how can I make this feature work for each user separately, so other users don't overwrite previous alarm times that were already ticking?
This method is called in the main code to start the countdown.
public void StartTimer(int seconds, GuildMessageReceivedEvent event)
{
timer = new Timer();
timer.schedule(new TimerReminder(event), seconds * 1000);
}
public void StartTimer(int seconds, GuildMessageReceivedEvent event, String text)
{
timer = new Timer();
timer.schedule(new TimerReminder(event, text), seconds * 1000);
}
I have this subclass that does a block of code after the .schedule() time.
class TimerReminder extends TimerTask{
GuildMessageReceivedEvent eventtrigger;
String alarmText = "";
private TimerReminder(GuildMessageReceivedEvent event)
{
eventtrigger=event;
}
private TimerReminder(GuildMessageReceivedEvent event, String alarmArg)
{
eventtrigger=event;
alarmText=alarmArg;
}
public void run()
{
if(alarmText.isEmpty())
{
eventtrigger.getChannel().sendMessage("<#"+auth+">, ***your alarm is ringing!***🔔🔔🔔🔔").queue();
timer.cancel(); // Terminate the timer thread
}
else
{
eventtrigger.getChannel().sendMessage("<#"+auth+">:\n"+alarmText).queue();
timer.cancel(); // Terminate the timer thread
alarmText="";
}
}
}
At the end of each task, you're running cancel on the timer reference which cancels not the timer that is currently running (Unless no one else ran the command) but rather the timer object that is assigned at the moment to the timer reference which makes it seem like the timers are overwriting each other.
And even if you kept a reference to all of the timers so you could cancel them, there's no need for you to cancel the timer after the task completes, the timer terminates itself.
Furthermore, there's no need for you to keep a static reference to the timer that is currently running, or keep a reference to them at all. When you create a timer a background thread keeps a reference to the timer and the task so they won't get garbage collected. You'd be better off creating the timer as a local variable when the command is run, scheduling the timer and that's it.
If you want the ability to cancel the timers by a different command or whatever you have in mind, then you should keep a list or map with references to all the current timers so you can cancel them if needed.
How do I run a specific set of instructions inside the TimerTask continuously without delay for a set amount of time ? Below are the codes I am attempting to implement the above.
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
System.out.println("Test started at: " + new Date());
// Do something continuously without delay
System.out.println("Test finished at: " + new Date());
}
}, 0);
The second parameter to the schedule method is the time to begin the timer task (or delay relative to now), not the length of time that the timer will execute for.
It's not completely clear from your question but I'm assuming you want the task to start and stop at particular times (or delays relative to now) in the future. If so, the way I would approach this is to create a Thread that does the task you need. Since a TimerTask is a Runnable that is executed as a Thread once the Timer starts it, you can just use an instance of that TimerTask. Ensure that Runnable contains a settable field like running. In that Thread, run your task in a while loop like this:
public void run() {
while(running) { /* do my task */ }
}
Then, use one Timer to schedule the Runnable to start at the time you need. Use another Timer to set the running parameter of the same Thread to false at the time you want it to stop. The running parameter should be volatile to ensure that changes to it from the second timer Thread are seen by the first timer Thread immediately. So it would look something like this (not tested):
class StoppableTimerTask extends TimerTask {
private volatile boolean running = true;
public void stopRunning() { this.running = false; }
public void run() {
while(running) { /* do my task */ }
}
}
final StoppableTimerTask task = new StoppableTimerTask();
timer.schedule(task, startTime);
timer.schedule(new TimerTask() {
public void run() {
task.stopRunning();
}
}, stopTime);
Depending on what your "something" is, you may also want to look into Thread interrupts. For example, if it is doing blocking IO, your code won't loop and check the running value until the blocking IO completes. Interrupting the thread (may) cause that to happen. See http://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#interrupt--. This may or may not work, and it can be tricky to get right, so if you need this Thread to exit as close to the desired time as possible, prefer running blocking I/O and similar operations with smaller timeouts so that the thread can check whether it should continue to run more often.
UPDATE: As per the comment indicating that the task should start right away, it becomes even simpler. The initial task doesn't even need to extend TimerTask -- it can just be a regular Thread that is started immediately. The timer is only needed to stop it at the specified future time.
Currently in my brief time with Java I have made a clicker game and I've been trying to implement a way to add a number to an integer (or the int command) every couple of seconds. but whatever I try just stops the entire program completely such as the
Thread.sleep(15000);
wait(15000);
even if they are in a try and catch it just stops the program and not complete a loop every couple of seconds.
If you have Thread.sleep(xxx); in the current thread, then yes, it will stop the current thread for xxx seconds. Because (most likely) Thread.sleep is in the same thread that is controlling the GUI, it is pausing your code from executing, freezing your application. There are two ways you can fix this:
Create a new thread and place the timer code in there:
SwingUtilities.invokeLater will add your Runnable to the queue of threads that AWT executes.
// Because the code is in a different thread, Thread.sleep(1000) will not pause
// the current thread and the application will continue as normal
Thread thread = new Thread(new Runnable() {
int seconds = 0;
#Override
public void run()
{
while (true) {
// wait one second
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
};
// increment seconds
seconds++;
System.out.println(seconds);
}
}
});
thread.start();
Use an existing timer in the Java API
Look at ScheduledThreadPoolExecutor and its scheduleAtFixedRate method. Here's an example. You could also use a swing timer as mentioned in the comment by Hovercraft Full Of Eels.
To use a Swing timer, you import javax.swing.Timer (not java.util.Timer), create a Timer object with the delay and an action listener listening for when it will fire events, and start it.
Timer timer = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent a)
{
System.out.println("Timer went off!");
}
});
// Repeat every second
timer.start();
Note that this code won't execute on its own; you need to have a GUI running.
I have scheduled a method to run at a certain date in the future; however, there are certain events that may or may not happen before that date that would mean I want to run the method earlier than the specified date; how can I do this? I currently have:
Timer timer = new Timer();
TimerTask task = new TaskToRunOnExpriation();
timer.schedule(task, myCalendarObject.getTime());
I will have many of these TimerTask's running in my application, stop specific instances of them if a certain even happens?
EDIT
I will only ever want to cancel a single Timer for a given event, is there a way of managing the identities for the Timers such that I can easily find and stop it?
If you have thousands of them you should use a ScheduledExecutorService which will pool threads rather than a Timer which will use one thread per timer.
The ScheduledFutures returned by the executor service when you schedule a task also have a cancel method to cancel the underlying tasks: future.cancel(true);.
As for cancelling the right task, you could store the futures in a Map<String, Future> so you can access them by name or id for example.
In C# I would say use delegates, but that is not an option in Java. I would work off this idea:
class Timers
{
Timer timer1;
Timer timer2;
ArrayList<Timer> timerList;
public Timers()
{
// schedule the timers
}
// cancel timers related to an event
public void eventA()
{
timer1.cancel();
timer2.cancel();
}
public void eventB()
{
for(Timer t : timerList)
t.cancel();
}
}
Use this schedule method.
public void schedule(TimerTask task,Date firstTime,long period)
task--This is the task to be scheduled.
firstTime--This is the first time at which task is to be executed.
period--This is the time in milliseconds between successive task executions
I use Timer in android to update a progress bar.Here is some of my code, hoping it can help you:
Timer timer ;
#Override
protected void onCreate(Bundle savedInstanceState) {
//....
timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
updateLogoBarHandler.sendEmptyMessage(0);
Log.e("SplashActivity","updating the logo progress bar...");
}}, 0, 50);
//.....
}
//here do the timer.cancel();
private Handler updateLogoBarHandler = new Handler() {
public void handleMessage(Message msg) {
if(logobarClipe.getLevel() < 10000){
logobarClipe.setLevel(logobarClipe.getLevel() + 50);
}else{
timer.cancel();
}
super.handleMessage(msg);
}
};
I need to perform a task repeatedly that affects both GUI-related and non GUI-related objects. One caveat is that no action should performed if the previous task had not completed when the next timer event is fired.
My initial thoughts are to use a SwingTimer in conjunction with a javax.swing.SwingWorker object. The general setup would look like this.
class
{
timer = new Timer(speed, this);
timer.start();
public void actionPerformed(ActionEvent e)
{
SwingWorker worker = new SwingWorker() {
#Override
public ImageIcon[] doInBackground() {
// potential long running task
}
#Override
public void done() {
// update GUI on event dispatch thread when complete
}
}
}
Some potential issues I see with this approach are:
1) Multiple SwingWorkers will be active if a worker has not completed before the next ActionEvent is fired by the timer.
2) A SwingWorker is only designed to be executed once, so holding a reference to the worker and reusing (is not?) a viable option.
Is there a better way to achieve this?
For (1), the scheduleAtFixedRate() method on ScheduledThreadPoolExecutor might be useful. From the javadocs:
If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.
For (2), it looks like you could define a subclass of SwingWorker and construct new instances of the subclass for each iteration, instead of instantiating an anonymous subclass.
Have you looked at using a simple Java Timer, and a ReadWriteLock to determine if a task is running when the timer triggers again ? In this situation you could simply bail out of that particular iteration and wait for the next.
Why do you use a Timer? It would be simpler to keep the 'worker' running all the time, pausing via sleep() whenever the task took too little time to complete. You can still update things in the event dispatch thread using something like the following:
Thread background = new Thread(new Runnable() {
public void run() {
while ( ! stopRequested ) {
long start = System.currentTimeMillis();
// do task
long elapsed = start - System.currentTimeMillis();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// update UI
}
});
if (elapsed < tickTime) {
Thread.sleep(tickTime - elapsed);
}
}
}
}.start();