Swing Timer in Conjunction with Possible Long-running Background Task
I need to perform a task repeatedly that affe开发者_运维知识库cts 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();
精彩评论