For those of you need to know, I'm writing a plugin for CraftBukkit, which is a modded version of Minecraft, and I'm a beginner level java programmer. I have what I think is a really basic question.
I'm trying to implement a countdown that executes methods to send messages to players every second for 20 seconds.
Obviously, I can't simply create a loop that loops for 20 seconds, because that loop will freeze the main thread until it finishes, which is unacceptable. (There is a lot of game code executing)
What are some approaches to creating a loop that will run passively or without halting the main thread?
The only thing I can possibly think is creating a new thread to run the countdown in.
Surely there is a simpler way to do this?
So you aren't confused, the countdown isn't initialized as part of some main loop, its initialized linearly by a user command listener, but its code executes in the main loop. What I mean by that is I need to actually START a loop that checks time, because this code is only executed once.
Sorry if I'm not being clear or making sense.
I would recommend java.util.Timer if you are not using Swing for GUI/Graphics (not familiar with CraftBukkit, so that will be up to you to determine). In particular, look at forms of schedule which allow a task to be repeated at fixed intervals.
javax.swing.Timer is similar. The biggest difference (aside from the interfaces used to respond to timers being triggered) is that javax.swing.Timer utilizes the EDT (event dispatch thread) to run events. If you're using a Swing GUI, this thread is already present and running and you want to use it. If you're not using Swing or AWT, then this is extra overhead that you don't need.
You would use a java.util.concurrent.Executors.newSingleThreadScheduledExecutor() and conveniently schedule a countdown task at 1-second intervals.
Alternatively, if you task must run on the Event Dispatch Thread (the "GUI thread"), you'll be better served by javax.swing.Timer.
Try javax.swing.Timer:
int delay = 1000; //milliseconds
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//...Perform a task...
}
};
new Timer(delay, taskPerformer).start();
Related
I'm trying to make "Realtime Feeling JTable". I made GUI with JTable, and then there is a button named START. When I click this button, the program will call below start() method. (It's just an example). Adding row is no problem, It works well. But the problem is, rows come to Jtable just at one time. (maybe program finish start() method, The rows come up with at all together.) There is 1000 more statement in my start() method. It's not realtime feeling. I shoud wait until start method finished. and then 1000 rows added at once.
void start(){
int a = 3+3;
addRow(new String[]{"a is 6"})
int b = 4+4;
addRow(new String[]{"b is 8 "})
}
What I'm gonna do is just "Real Time Feeling", I want to see adding row one by one, not at once. Could you understand my purpose? Imagine "Fiddler" Program. you can understand easily. Can anyone help me? Should I make a Thread?
Thanks for reading, and sorry for ackward expression(english is not my language)
This is because of the way Swing threading works. There is one single thread that handles all rendering, updating, etc. Your processing of the start() method is happening inside that render thread so nothing else on the GUI will respond until you return from the method.
What you need to do is use a SwingWorker or a ThreadPoolExecutor and farm the processing off to another thread. That can then update the GUI on a regular basis as the processing continues.
http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
Note that by doing this people can potentially click the button multiple times and call start() again before the first one has finished. You will need to consider and handle that case - for example by disabling the button until the first one completes.
Use a Swing based Timer. In the actionPerformed(..) add a new record. See How to Use Swing Timers for details.
In swing there is a thread called EDT (Event Dispatcher Thread) that is responsible for GUI to behave like a real time, user friednly app. If you interfer EDT with a long running method you will freeze your app GUI. You have to do long running tasks in background (in a thread different than EDT). You can do this by using javax.swing.SwingWorker<T,V> or javax.swing.Timer
I´m developing a Swing application. I need to run some tasks in background that, as a result, need to display messages on the TrayIcon. Those tasks must execute repeatedly, after some fixed delay, so i research and found Swing Timers as a good option. However, at the same time those tasks can be time consuming, and i don´t want that the GUI freezes or something like that (so, in order to fullfill this last requiriment i should go with Worker Threads instead). The thing is that worker threads don´t allow me to execute this tasks with some fixed delay and "forever".
I don´t know how to solve this, so any help would be appreciated :)
Have the actionPerformed of the Timer create a SwingWorker for the actual work.
you needn't create any extra multithreading support. timers create a new thread for running the commands in actionPerformed. alternatively you may also use 'java.util.Timer' as your timer. it is easier than swing and it also creates automatic threads each time you run.
import java.util.*;
after this you may add
Timer t=new Timer();
t.scheduleAtFixedRate(new TimerTask(){
void run(){
// your codes to perform
}, /*time in miliseconds*/);
this may solve your problem
You can create your task queue.
Create a Timer, that will shedule your task to some executor. (like ThreadPoolExecutor). At any delay, periodically, an so on.
Register a listener to task completion.
Executor will work with task on background.
When task is ready, notify main application via callback.
Do not work with simple threads. Java has a lot of concurent machanics, like Future and Executors.
I am using the following codes, to replace a JLabel each 0.5 seconds, with the same sentence but with another dot.
Runnable r1=new Runnable() {
#Override
public void run() {
while(true){
try {
connectionStatus.setText("Connection Established...");
Thread.sleep(500L);
connectionStatus.setText("Connection Established.");
Thread.sleep(500L);
connectionStatus.setText("Connection Established..");
Thread.sleep(500L);
} catch (InterruptedException ex) {
}
}
}
};
Thread th1=new Thread(r1);
th1.start();
Is this the real purpose from using threads? Does this affect the speed of the program? If the thing that I'm doing is so stupid, is there any other way to do such stupid things?
Is this the real purpose from using threads?
If you want these operations to run in parallel then the answer is yes
is there any other way to do such stupid things?
If you update your label at a fixed intervals then you should probably go for using Timers instead
On a side note:
You should avoid using while(true) when doing multithreading, you should either define a stop boolean that you test in the loop or use Thread.interrupted() if you extend the Thread class
When updating UI elements from non EDT thread, you should use SwingUtilities.invokeLater
There are several issues with this code.
Swing components should be accessed/updated on the Event Dispatch Thread and are not thread-safe. So starting another Thread to update your JLabel is simply not done. See the 'Concurrency in Swing' tutorial for more information
Even if you would call the code above on the EDT, you would not see any updates of the JLabel as the Thread.sleep would block the EDT, and avoiding a repaint.
So the solution is to use the javax.swing.Timer class, which allows to perform operations on the EDT at regular intervals, and does not block the EDT in between. See also the Timer tutorial. As a side effect, using timers avoids the while(true) loop which would never end.
You can find a more complete answer here.
Try using a Timer from Swing library instead. It's generally a better idea to use these for GUI-related tasks. This will especially come in handy when you try to use timed events on multiple components as all Timers share the same timer thread.
It also provides a flexible and intuitive programming model based on listeners.
No need to reinvent the wheel.
Timer tutorial
EDIT:
A little followup on the wheel reinvention part. You should also take Andrew Thompson's suggestion into consideration. There are components in Swing that have been designed specifically to indicate progress. It's unnecessary to do it using a label, as you're trying to do. Take a look at JProgressBar. It's going to be simple and it will look more professional.
First one suggestion, rather use something like this:
while(!isStopped) {
// do some work
}
With your approach you just created infinity loop.
Note: Have look at Java Timer. It's very usefull and efficient.
Try this,
You will need the above approach if your purpose is parallel processing.
You have given while (true) , which will lead to a Infinite loop, you must control it,
its better to have a boolean variable to control the nos. of iteration of the while loop.
Keep you non-ui thread processing OUT of the Event Dispatcher Thread, else you will make the GUI hang till
your thread has finished its run() method. In your case its Infinite, as while (true).
If you want to sync the non-ui work and ui work, then you can use Handler or Swing-Worker.
Last but not the least, Take a look at TimeTask, see this link
http://enos.itcollege.ee/~jpoial/docs/tutorial/essential/threads/timer.html
I've searched for a solution for my problem all over but I cannot find anything close. Here is my problem: I have just started to learn Swing in Java and I have an application that will click randomly between a min and max amount of time. The user enters a min and max time and clicks a button which starts this code:
class CalcButtonListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent arg0) {
//get data from text fields and store as integers in milliseconds.
//create a robot and random number between min and max
while(run == true){
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
robot.delay(num.nextInt(max-min+1)+min);
}
}
}
}
I've removed some code because it wasn't relevant to the issue.
The problem is I have another button to set the variable run to false but once the first button is clicked, I can't click the second button or the exit button at the top for that matter.
I'm sure my mistake is a very basic one but I can't see it.
Thank you for any replies that help me better understand the subject.
Edit: Changed the while loop from "while (run = true)" to "while (run == true)".
while(run == true){
"=" sets run to true
"==" compares the value of run to true
Also you can just use
while(run){
Take a look at SwingWorker. And just do while(run)
Every event will be processed by a single thread called Event Dispatch thread(EDT). If you have an infinite call inside one of the events, EDT cannot process the next event in the event queue.
UPDATE
This answer is updated, because #uckelman pointed me out that, with the condition run = true, the stop button never breaks the while loop, because it's needed to change to run = false within the loop. Then I post a simple and alternative solution to this logic problem, to schedule a task repeatedly with a timer. For details, please check this SO question.
About the events for the buttons: if you have two buttons, one to start a loop and one to end the loop, just try this code:
class CalcButtonListener implements ActionListener{
private boolean run = true;
private java.util.Timer timer = new java.util.Timer();
private JButton start_loop, end_loop;
//here the buttons initialization
#Override
public void actionPerformed(ActionEvent ae){
if(ae.getSource()==start_loop){
java.util.TimerTask task = new java.util.TimerTask() {
#Override
public void run() {
doStuff();
}
};
timer.schedule(task, java.util.Calendar.getInstance().getTime(), 500);//here the '500' means the time, 500 ms,
the task is repeatedly executed.
}
if(ae.getSource()==end_loop){
timer.cancel();//cancel the tasks scheduled
System.out.println("Task cancelled!");
}
}
private void doStuff(){
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
robot.delay(num.nextInt(max-min+1)+min);
}
}
Now, the task doStuff() is scheduled to be executed each 500 ms.
Other info about java.util.Timer and java.util.TimerTask.
About your problem:
The problem is I have another button to set the variable run to false
but once the first button is clicked, I can't click the second button
or the exit button at the top for that matter.
As in a previous question, and in this page, it's written this:
Swing's single-thread rule says that Swing components can only be
accessed by a single thread. This rule applies to both gets and sets,
and the single thread is known as the event-dispatch thread.
The single-thread rule is a good match for UI components because they
tend to be used in a single-threaded way anyway, with most actions
being initiated by the user. Furthermore, building thread safe
components is difficult and tedious: it's a good thing not to be doing
if it can be avoided. But for all its benefits, the single-thread rule
has far-reaching implications.
Swing components will generally not comply with the single-thread rule
unless all their events are sent and received on the event-dispatch
thread. For example, property-change events should be sent on the
event-dispatch thread, and model-change events should be received on
the event-dispatch thread.
For model-based components such as JTable and JTree, the single-thread
rule implies that the model itself can only be accessed by the
event-dispatch thread. For this reason, the model's methods must
execute quickly and should never block, or the entire user interface
will be unresponsive.
Then, if you develop your GUI using a single Thread, when a button event is executed, your GUI will freeze, waiting for the complete execution of the related button event. In your case, on a infinite loop, your GUI will always freezing.
My suggestion is to use, for your GUI, a SwingWorker, or extend the Thread class (then developing the GUI in a separate thread), or implement the Runnable interface. Another alternative is the using of a Timer from the javax.swing.Timer package.
You can read this old question of SO about SwingWorker: How do I use SwingWorker in Java?
A tutorial for SwingWorker : http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
A tutorial to make a Thread : http://docs.oracle.com/javase/tutorial/essential/concurrency/
A question about Timer: Update JPanel and attributes in a gui, with a user-specified timer?
A tutorial about Timer: http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html
You should read about Swing timers:
http://java.sun.com/products/jfc/tsc/articles/timer/
That is, make your program event-driven. Swing applications already have a loop running inside them all the time, called the event loop. It doesn't help if you start another one.
Be careful about method like while(something), this could make the program frezee, i recommend you to implement events listeners to avoid this problems...
run=true;
while(run == true){
...
while (run = true) is almost certainly not what you want. What that does is assigns true to run each time the loop condition is executed, which ensures that the loop will always continue.
What you were probably trying to say was while (run == true) which only tests whether run is true. Better is just to say while (run), which does the same thing.
If you're assigning to run from a different thread, note that you ought to make run a volatile member of your class. If you're not assigning to run somewhere else, then you have a logic bug, since there's no way to break out of the loop. In that case, you need to add a test inside the loop and set run to false when you want the loop to stop. (Or, you could have while (true) and just use a break inside the loop.)
I have 3 timers running on my application which takes care of different action. Timer 1 will deals with automatic logout of the application, timer 2 deals with updating a table, timer 3 deals with updating the color of swing buttons. First timer uses the calculation based on the variables and its values, second and third timers works out of MYSQL queries.
Now when i run this application on an average performance machine the application is not moving .I need to wait for few seconds to a normal click to happen or a window to open. Is it something to do with the timers ? If yes do I have any alternative suggestions to get rid of this timer problem?
It could well be the timers, if they are performing considerable work when fired. It's not usually a good idea to use swing timers for long-running tasks, since they will block the EDT and freeze the UI.
Here are some suggestions to avoid this:
Use a java.util.Timer rather than the swing timer. This will run the database code on a background thread, avoiding blocking the event queue.
Continue to use the swing timer, but have the timer action simply start a SwingWorker to perform the task. This gives the benefit of background processing with the ability to post updates to your UI, if it's a operation that takes more than a second or so to execute.
The problem isn't how many timers you have, but how long each timer takes to do it's work, since the timer's actionPerformed method is run on the swing event thread, meaning that while a timer is doing it's thing, no UI updates can happen.
That should not be related to the Swing timers, that is something else in your code. You need to debug the application to see what is causing the delay.
From what I remember, swing timers fire events on the same thread used for rendering, so you dont tend to get exceptions due to incorrect thread interractions - I have used them in the past for animations without issue - I suspect the answer lies elsewhere in your code. Have you tried profiling the code at the point where you are having an issue?
Is it OK if I run 5 timers at the same time?
All instances of javax.swing.Timer "perform their waiting using a single, shared thread." The limit occurs when the tread becomes saturated. As a practical matter, each Timer may have multiple listeners, but "the handlers must execute quickly to keep the GUI responsive."