Background job running without affecting the rest of the gui
I'm asking for assistance concerning a general approach.
I have written some java code to check my mailbox for unread mails on buttonclick.
Now I want this code to permanently run in the background and check my mailbox every 2 minutes.
Bad idea:开发者_运维技巧
while(true)
{
checkMails();
Thread.sleep(120000);
}
The rest of the graphical interface obviously freezes, so there has to happen some magic with threads, I suppose.
How could this be realized?
Either use a javax.swing.Timer
, or SwingWorker
, although the latter is a bit overkill in this scenario.
If this task does not modify any Swing components, then why not just spawn a separate thread, as such
Thread t = new Thread(new Runnable(){
@Override
public void run(){
while(!Thread.currentThread().isInterrupted()){
//do stuff
try{
Thread.sleep(120000);
}catch(InterruptedException e){
Thread.currentThread().interrupt();
}
}
}
});
t.start();
It's important to note that you'll probably want to use a boolean
to ensure that the thread is only created once, since there's the potential that a new thread will spawn with each button click, which is probably not what you want.
Why don't you just spawn a seperate thread that will handle the checkMails()
and perform that action you already have. Just be careful when you update your GUI.
Thread thread = new Thread(new Runnable() {
public void run() {
while (true) {
checkMails();
Thread.sleep(120000);
}
}
});
edit: Maybe you should add a check somewhere in the case you want to stop the checking for new mail (for whatever reason). Also you got to call thread.start();
Use a javax.swing.Timer
. Something like this:
int delay = 120000;
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
checkMails();
}
};
new Timer(delay, taskPerformer).start();
You need to use threading to solve this. Threads are like multitasking.
Thread t = new Thread(){
public void run(){
//do job
}
}
t.start(); //starts the thread
To end the thread, you'll need some kind of stopping condition
public boolean run = false;
Thread t = new Thread(){
public void run(){
while(run)
//do job
}
}
public void startThread(){
t.start(); //starts the thread
}
See also:
- Introduction to threads
- The Javadoc for Thread.
Thread.stop()
will kill the thread, but this is very bad. For example, suppose that you're writing into an array
for(int i = 0; i < myAr.length; i++)
myAr[i] = getStuff(i);
And at i = 5
, Thread.stop()
is called. Now your program thinks that everything is good, when in fact, it's not!
To kill the thread, set run
to false
. run
is a boolean
I showed in the second example. The other option is to create a subclass of Thread
(not just in line overriding methods) and create a method halt()
(stop
is final). halt()
will set run
to false. run
will still be a global boolean
.
Here's an example of that.
public class MyThread extends Thread {
public boolean run = true;
public void run(){
run = true;
while(run)
doStuff();
}
public void halt(){
run = false;
}
}
You need to be careful that two threads aren't modifying the same object at once, it would be like turning an object into a random number generator :/
Now that you have been given the power of threads, use it wisely, for good not for evil! Go forth and be thread-safe.
A few ideas:
1) Create a java.util.Timer
that fires periodically, checking the mailbox for messages and updating the GUI using SwingUtilities#invokeLater
;
2) Create a timer (either java.util.Timer
or javax.swing.Timer
) that schedules a javax.swing.SwingWorker
to both check the mailbox and update the GUI.
3) Create a Thread
that checks the mailbox, updates the GUI using SwingUtilities#invokeLater
and sleeps for some time;
I'd use 1 or 2, because you can just stop the timers if you ever need to cancel the task.
Obviously you need to use EDT if you need to update the UI after finishing the checkMails() method.
And you are looking for asynchronous (other one is synchronous) way.
Certainly you are looking for SwingUtilities.html#invokeLater(java.lang.Runnable)
According to my knowledge, this is the correct way to do background task for Swing.
Runnable checkMail = new Runnable() {
public void run() {
while(true) {
checkMails();
Thread.sleep(120000); //but this is very naive approach to use sleep, consider using timer ;)
}
}
};
SwingUtilities.invokeLater(checkMail);
invokeLater(Runnable doRun): Causes doRun.run() to be executed asynchronously on the AWT event dispatching thread.
and
invokeAndWait(Runnable doRun): Causes doRun.run() to be executed synchronously on the AWT event dispatching thread.
精彩评论