Java 与可能长时间运行的后台任务一起使用Swing计时器

Java 与可能长时间运行的后台任务一起使用Swing计时器,java,swing,Java,Swing,我需要重复执行一项任务,该任务会影响GUI相关和非GUI相关的对象。一个警告是,如果在触发下一个计时器事件时上一个任务尚未完成,则不应执行任何操作。 我最初的想法是将SwingTimer与javax.swing.SwingWorker对象结合使用。一般设置如下所示 class { timer = new Timer(speed, this); timer.start(); public void actionPerformed(ActionEvent e)

我需要重复执行一项任务,该任务会影响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之前工作进程尚未完成,则多个SwingWorker将处于活动状态

2) SwingWorker设计为只执行一次,因此保留对worker的引用并重用(不是?)是可行的选择


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

您有没有考虑过使用简单的Java计时器,以及在计时器再次触发时确定任务是否正在运行?在这种情况下,您可以简单地退出该特定迭代并等待下一次迭代。

您是否考虑过使用简单的Java计时器和一个确定计时器再次触发时任务是否正在运行的方法?在这种情况下,您只需退出特定的迭代并等待下一次。

为什么要使用计时器?让“worker”一直运行会更简单,只要任务完成时间太少,就通过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();
Thread background=新线程(new Runnable()){
公开募捐{
而(!stopRequested){
长启动=System.currentTimeMillis();
//做任务
长时间运行=启动-System.currentTimeMillis();
SwingUtilities.invokeLater(新的Runnable(){
public void run(){
//更新用户界面
}
});
如果(经过的时间<滴答声时间){
睡眠(滴答声时间-已过);
}
}
}
}.start();

为什么要使用计时器?更简单的方法是让“worker”一直运行,在任务完成时间太少时通过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();
Thread background=新线程(new Runnable()){
公开募捐{
而(!stopRequested){
长启动=System.currentTimeMillis();
//做任务
长时间运行=启动-System.currentTimeMillis();
SwingUtilities.invokeLater(新的Runnable(){
public void run(){
//更新用户界面
}
});
如果(经过的时间<滴答声时间){
睡眠(滴答声时间-已过);
}
}
}
}.start();
对于(1),
ScheduledThreadPoolExecutor
上的
scheduleAtFixedRate()
方法可能有用。来自javadocs:

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

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

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

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

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