I am trying to create a program to perform a simple task and produce an output every x seconds. I also want the program to run until I decide to manually close the program.
I have been attempting to implement this using a Swing timer, as I believe this is the best way. The problem is I'm not sure how to keep the program going once the main method has finished executing. So for example I have:
static ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
try {
//do stuff
} catch (Exception e) {
e.printStackTrace();
}
}
};
public static void main(String[] args) throws Exception{
Timer timer = new Timer(3000, taskPerformer);
timer.start();
}
which just finishes execution immediately. I can dodge the problem by putting the current thread of execution to sleep Thread.currentThread().sleep(..), but this feels like a botch job, and will be ultimately be finite in duration. I can also do while(true), but I believe this is bad practice.
My question is how to get the desired persistence behavior, and if there is a better way than using Swing timers.
Thanks.
A Swing Timer will stay alive as long as the EDT is alive, usually this is done by having a Swing GUI present and visible (this creates a non-daemon thread that persists until the GUI exits). If you don't need a Swing GUI, then don't use a Swing Timer. Perhaps instead use a java.util.Timer, and don't exit the main method til you give the word (however you plan to do that).
Use java.util.Timer instead. The associated thread will not run as a daemon.
Related
I'm building a user-interface with Java's swing library, and I've run into a problem.
When updating a text-area in a long method, there is a pause while the method runs, and then the text area is updated all at once, instead of a little bit at a time.
I managed to fix the problem using a new thread in the following manner:
private void jButtonActionPerformed(java.awt.event.ActionEvent evt) {
Thread x = new Thread() {public void run() {
// do things that update a text area
}}; x.start();
}
This works perfectly for having the text area update in small pieces, as opposed to all at once.
However, the only problem is that this method can only be called once or Java crashes. I read that this has to do with only being able to create the thread one time. How can I modify the code to keep the desired functionality?
Any help would be greatly appreciated.
Well, I doubt you codes crashing because of the Thread creation, because each time the method is called, you're creating a new Thread (you can't restart an existing instance of a Thread that has already been started (even if it's completed or not)), the likely cause is you're getting a concurrent modification exception because Swing is not Thread safe...
Probably the easiest solution would be to use a SwingWorker which will allow you to execute your long running task in the background, but provide easy to use functionality to update the UI safely, through the publish, process and done methods.
Do prevent possible issues, you might also consider disabling the button until the load action is completed, which will prevent people from mashing the button spawning multiple background processes...
Well you can make new object of the Thread and override all the method means runnable.
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
System.out.println("Executed..*****");
}
}).start();
try this.
Just for comparison's sake, here is an example using SwingUtilities.invokeLater. I echo MadProgrammer's advice though, learning about SwingWorker is much more beneficial in the long term and gives better variable handling.
newGame.addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent arg0) {
panelList.get("newGame").setEnabled(false);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// this is where the heavy processing occurs
newGameButton();
// re-enables the button afterwards
panelList.get("newGame").setEnabled(true);
}
});
}
});
Also, once your code is working better, you can probably look into ways to optimise the speed of the update (even when dealing with Swing objects). The above call used to hang for a second or so, but I've got the delay to about 50 - 100ms or so with further work on the model :)
I im creating a simple testing app that runs a check every hour on the selected directory/s using thread.sleep() through JFileChooser. But when i select the directory and the method runs the ui panel goes grey and the swing bits disappear. The thread seems to be putting the ui to sleep as well as the method its calling.
if (option == JFileChooser.APPROVE_OPTION) {
selectedDirectory = chooser.getSelectedFiles();
try {
while (true) {
runCheck(selectedDirectory);
Thread.sleep(1000*5);//1000 is 1 second
}
} catch (InterruptedException e1) {
Thread.currentThread().interrupt();
e1.printStackTrace();
}
}
Im looking for a way around this issue so that i can print the results of the checks being run in the ui .setText(result)
You are correct about the code putting the UI to sleep. Since sleep is called on the Event Dispatch Thread (the thread responsible for running the gui) the UI stops processing events and 'goes to sleep'.
I think what you want is a javax.swing.Timer.
Timer t = new Timer(1000 * 5, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// do your reoccuring task
}
});
This will cause your reoccurring task to be performed off of the EDT, and thus it wont leave your ui unresponsive.
If the code you have posted runs on the EventDispatchThread, then there is no way Swing can redraw the GUI. You're blocking (sleeping in) the thread that's supposed to handle that!
This is because you are running you check in the main GUI thread and are using an infinite loop. This check is a background task and should be executed in it's own thread so that the GUI can still receive and react to input by the user.
You also do not need to write your own implementation, Java has a Timer object.
Edit: There is also a Swing specific Timer object. This will have the action occur in the GUI thread, so if your task is long, it can cause the GUI to still lock up while the action is occurring (but not while it is waiting).
I im creating a simple testing app that runs a check every hour on the selected directory/s using thread.sleep() through JFileChooser. But when i select the directory and the method runs the ui panel goes grey and the swing bits disappear. The thread seems to be putting the ui to sleep as well as the method its calling.
if (option == JFileChooser.APPROVE_OPTION) {
selectedDirectory = chooser.getSelectedFiles();
try {
while (true) {
runCheck(selectedDirectory);
Thread.sleep(1000*5);//1000 is 1 second
}
} catch (InterruptedException e1) {
Thread.currentThread().interrupt();
e1.printStackTrace();
}
}
Im looking for a way around this issue so that i can print the results of the checks being run in the ui .setText(result)
You are correct about the code putting the UI to sleep. Since sleep is called on the Event Dispatch Thread (the thread responsible for running the gui) the UI stops processing events and 'goes to sleep'.
I think what you want is a javax.swing.Timer.
Timer t = new Timer(1000 * 5, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// do your reoccuring task
}
});
This will cause your reoccurring task to be performed off of the EDT, and thus it wont leave your ui unresponsive.
If the code you have posted runs on the EventDispatchThread, then there is no way Swing can redraw the GUI. You're blocking (sleeping in) the thread that's supposed to handle that!
This is because you are running you check in the main GUI thread and are using an infinite loop. This check is a background task and should be executed in it's own thread so that the GUI can still receive and react to input by the user.
You also do not need to write your own implementation, Java has a Timer object.
Edit: There is also a Swing specific Timer object. This will have the action occur in the GUI thread, so if your task is long, it can cause the GUI to still lock up while the action is occurring (but not while it is waiting).
Hi
i am trying to create multi JFrames but I want each one to has its own Thread (message loop) ,so when one JFrame freezes the others will keep working
i tried to create each jframe from different Threads, but they are still working in the "AWT-EventQueue-0" thread.
i come from a dotnet background. so when i want to do this scenario in a winForms app i usually call
Application.run(new form())
from a new thread
can u please tell me how to do this in java ?
thanks in advance!
There is only UI thread in Java, no matter how many frames you open. I would suggest you to execute the long running operation within a thread.
public void actionPerformed(ActionEvent e)
{
new Thread(new FrameRunnable()).start();
}
public class FrameRunnable implements Runnable
{
public void run()
{
// Do stuff here
}
}
Hope this will help.
Read the section from the Swing tutorial on Concurrency to understand how the Event Dispatch Thread works. All updates to GUI components must be done on the EDT. If you have long running tasks, you can use a SwingWorker or a separate Thread along with SwingUtilities.invoke(...) later to add code to the EDT.
Create a new thread for each JFrame generated. Take note of your Thread variables and pass it around on your Runnable.
Okay, I tested this on an empty program, and just having a while(true){} running gave me >50% on my CPU. I have a game I'm working on that uses a while loop as it's main loop, and it's CPU is at 100 all the time.
How can I get Java to repeat something over and over without eating up >50% of my CPU just to do the repeating?
Add a sleep to put the thread into idle for some interval:
Thread.sleep
Without having a sleep, the while loop will consume all the computing resources that is available. (For example, theoretically, 100% in a single core system, or 50% in a dual core, and so on.)
For example, the following will cycle once through a while loop approximately every 50 milliseconds:
while (true)
{
try
{
Thread.sleep(50);
}
catch (Exception e)
{
e.printStackTrace();
}
}
This should bring down the CPU utilization quite a bit.
With a sleep in the loop, the operating system will also give enough system time for other threads and processes to do their things, so the system will be responsive as well. Back in the days of single core systems and operating systems with not-so-good schedulers, loops like this could have made the system very unresponsive.
Since the topic of use of while loops for a game came up, if the game is going to involve a GUI, the game loop must be in a separate thread or else the GUI itself will become unresponsive.
If the program is going to be a console-based game, then threading is not going to be an issue, but with graphical user interfaces which are event-driven, having a long-living loop in the code will make the GUI unresponsive.
Threading and such are pretty tricky areas of programming, especially when getting started, so I suggest that another question be raised when it becomes necessary.
The following is an example of a Swing application based in a JFrame which updates a JLabel that will contain the returned value from System.currentTimeMillis. The updating process takes place in a separate thread, and a "Stop" button will stop the update thread.
Few concepts the example will illustrate:
A Swing-based GUI application with a separate thread to update time -- This will prevent lock up of the GUI thread. (Called the EDT, or event dispatch thread in Swing.)
Having the while loop with a loop condition that is not true, but substituted with a boolean which will determine whether to keep the loop alive.
How Thread.sleep factors into an actual application.
Please excuse me for the long example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TimeUpdate
{
public void makeGUI()
{
final JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JLabel l = new JLabel();
class UpdateThread implements Runnable
{
// Boolean used to keep the update loop alive.
boolean running = true;
public void run()
{
// Typically want to have a way to get out of
// a loop. Setting running to false will
// stop the loop.
while (running)
{
try
{
l.setText("Time: " +
System.currentTimeMillis());
Thread.sleep(50);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
// Once the run method exits, this thread
// will terminate.
}
}
// Start a new time update thread.
final UpdateThread t = new UpdateThread();
new Thread(t).start();
final JButton b = new JButton("Stop");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
t.running = false;
}
});
// Prepare the frame.
f.getContentPane().setLayout(new BorderLayout());
f.getContentPane().add(l, BorderLayout.CENTER);
f.getContentPane().add(b, BorderLayout.SOUTH);
f.setLocation(100, 100);
f.pack();
f.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new TimeUpdate().makeGUI();
}
});
}
}
Some resources about threading and using Swing:
Threads and Swing
Lesson: Concurrency
Thread.Sleep may not be the whole answer. For most games, there's way too much CPU for the amount of work needed. Simply sleeping for a set amount of time isn't all that efficient, since you will likely either still burn too many resources, or not enough. You typically want to time your work in some way.
If you think about it, the screen only updates at a certain rate, typically less than 100 times per second. I'm not familiar with the Java api's for this sort of thing, but what you want is to find out the refresh speed of the monitor and then update only a single time between each refresh.
Further, you don't need a loop like that for your main loop, you can use timers to call your update code at a regular interval. This is even more efficient.
You are indeed busy-waiting, meaning you are grinding your CPU constantly on checking one or more conditions until they are true.
Thread.sleep() is not the solution. Using wait() and notify() methods allows you to do just what you are trying, but much more efficiently. Basically, this mechanism allows a thread to sleep on an object until the object decides something has happened and wants to wake all the threads sleeping on it.
Code exmaples can be found here and here.
This should be your solution, and not hiding your busy-wait with a timer.
While yes, you could do a
Thread.sleep(50)
like the accepted answer suggest, you could also call
Thread.sleep(0)
This will tell the processor to do a context switch. Other threads waiting to be executed (like the GUI drawing thread) will then be executed and the machine will stop feeling slow.
The sleep(0) way will also maximise the time given by the OS to you application because the thread will immediatly go back in the processor's queue (instead of waiting 50ms before doing so) so if no other thread where waiting, you thread will continue being executed.
Usually in a game loop you will pause for a bit... for example: http://developers.sun.com/mobility/midp/articles/game/
It seems like your thread is busywaiting. That is to say, it is trapped in a loop in which it does nothing. In such a situation, it will chew up a lot of cpu cycles to no effect.
As mentioned by others, Thread.sleep is the answer.
That's swing-related, but the idea stays the same: try to use Observer pattern instead of wile(true).
How about a Quartz-Spring based scheduler that keeps doing the work over and over again in repeated intervals.
If there is an interrupt it is probably for a reason. A better way to handle this is
try {
while (true) {
Thread.sleep(50);
}
} catch (InterruptException e) {
Thread.currentThread().interrupt();
}
However this loop doesn't do anything, so I suggest you just delete it. It is fairly rare that you want to busy wait for a condition (In which case the Condition class is a better choice) usually you can transform the same behaviour not to need a loop at all.