Swing Timer与可能的长时间运行后台任务相结合

时间:2010-04-07 15:12:11

标签: java swing

我需要反复执行一项影响GUI相关和非GUI相关对象的任务。需要注意的是,如果在触发下一个计时器事件时前一个任务尚未完成,则不应执行任何操作。 我最初的想法是将SwingTimer与javax.swing.SwingWorker对象结合使用。一般设置看起来像这样。

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
            }
    }
}

我用这种方法看到的一些潜在问题是:

1)如果工作人员在计时器触发下一个ActionEvent之前尚未完成,则多个SwingWorkers将处于活动状态。

2)SwingWorker只设计执行一次,因此持有对worker的引用并重用(不是?)一个可行的选项。

有没有更好的方法来实现这一目标?

3 个答案:

答案 0 :(得分:1)

您是否考虑过使用简单的Java Timer和ReadWriteLock来确定当计时器再次触发时任务是否正在运行?在这种情况下,你可以简单地摆脱那个特定的迭代并等待下一个迭代。

答案 1 :(得分:1)

为什么使用定时器?保持“工人”一直运行会更简单,只要任务花费的时间太少,就可以通过sleep()暂停。您仍然可以使用以下内容更新事件派发线程中的内容:

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();

答案 2 :(得分:1)

对于(1),scheduleAtFixedRate()上的ScheduledThreadPoolExecutor方法可能有用。来自javadocs:

  

如果执行此任务的时间超过其周期,则后续执行可能会延迟,但不会同时执行。

对于(2),看起来您可以定义SwingWorker的子类并为每次迭代构造子类的新实例,而不是实例化匿名子类。