是否连续暂停/停止和启动/恢复Java TimerTask?

Fai*_*aiz 19 java multithreading android asynchronous timer

我有一个关于Java TimerTask的简单问题.如何根据特定条件暂停/恢复两个TimerTask任务?例如,我有两个在彼此之间运行的计时器.当在第一计时器的任务内满足某个条件时,第一计时器停止并启动第二计时器,并且当在第二计时器的任务内满足某个条件时发生相同的事情.下面的课程显示了我的意思:

public class TimerTest {
    Timer timer1;
    Timer timer2;
    volatile boolean a = false;

    public TimerTest() {
        timer1 = new Timer();
        timer2 = new Timer();     
    }

    public void runStart() {
        timer1.scheduleAtFixedRate(new Task1(), 0, 1000);
    }

    class Task1 extends TimerTask {
        public void run() {
            System.out.println("Checking a");
            a = SomeClass.getSomeStaticValue();

            if (a) {
                // Pause/stop timer1, start/resume timer2 for 5 seconds
                timer2.schedule(new Task2(), 5000);
            }
        }
    }

    class Task2 extends TimerTask{
        public void run() {
            System.out.println("Checking a");
            a = SomeClass.getSomeStaticValue();

            if (!a) {
                // Pause/stop timer2, back to timer1
                timer1.scheduleAtFixedRate(new Task1(), 0, 1000);
            }

            // Do something...
        }
    }

    public static void main(String args[]) {
        TimerTest tt = new TimerTest();
        tt.runStart();      
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我的问题是,如何timer1在运行时暂停,timer2反之亦然timer2?性能和时间是我的主要关注点,因为这需要在另一个正在运行的线程中实现.顺便说一句,我试图在Android上实现这些并发计时器.

谢谢你的帮助!

cle*_*tus 25

来自TimerTask.cancel():

请注意,从重复计时器任务的run方法中调用此方法绝对可以保证计时器任务不会再次运行.

所以一旦取消,它将不会再次运行.你最好使用更现代的ScheduledExecutorService(来自Java 5+).

编辑:基本结构是:

ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(runnable, 0, 1000, TimeUnit.MILLISECONDS);
Run Code Online (Sandbox Code Playgroud)

但是在调查它时,没有办法在没有关闭服务的情况下取消该任务,这有​​点奇怪.

TimerTask在这种情况下可能会更容易,但是当你启动一个实例时,你需要创建一个新实例.它不能重复使用.

或者,您可以将每个任务封装为单独的临时服务:

final ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
Runnable task1 = new Runnable() {
  public void run() {
    a++;
    if (a == 3) {
      exec.shutdown();
      exec = Executors.newSingleThreadScheduledExecutor();
      exec.scheduleAtFixedRate(task2, 0, 1000, TimeUnit.MILLISECONDS)
    }
  }
};
exec.scheduleAtFixedRate(task1, 0, 1000, TimeUnit.MILLISECONDS);
Run Code Online (Sandbox Code Playgroud)


Son*_*ang 15

我找到的最简单的解决方案:只需在计时器任务的运行代码中添加一个布尔值,如下所示:

timer.schedule( new TimerTask() {
    public void run() {
       if(!paused){
           //do your thing
       }
    }
 }, 0, 1000 );
Run Code Online (Sandbox Code Playgroud)

  • 我相信这不高效.定时器将继续运行并每次检查布尔值. (6认同)

Osc*_*Ryz 7

如果您已经取消了一个计时器,则无法重新启动它,您必须创建一个新计时器.

看到这个答案,它包含一个视频和源代码我是如何做类似的事情的.

基本上有两种方法:pauseresume

暂停时:

public void pause() {
    this.timer.cancel();
}
Run Code Online (Sandbox Code Playgroud)

简历中:

public void resume() {
    this.timer = new Timer();
    this.timer.schedule( aTask, 0, 1000 );
}
Run Code Online (Sandbox Code Playgroud)

这使得暂停/恢复的感觉.

如果您的计时器根据应用程序的状态执行不同的操作,您可以考虑使用StatePattern

拳头定义一个抽象状态:

abstract class TaskState  {
    public void run();
    public TaskState next();
}
Run Code Online (Sandbox Code Playgroud)

并提供您喜欢的多个州.关键是一个州引导你到另一个州.

class InitialState extends TaskState {
    public void run() {
        System.out.println( "starting...");
    }
    public TaskState next() {
         return new FinalState();
    }
 }
 class FinalState extends TaskState  {
     public void run() {
         System.out.println("Finishing...");
     }
     public TaskState next(){
         return new InitialState();
    }
 }
Run Code Online (Sandbox Code Playgroud)

然后你改变计时器中的状态.

Timer timer = new Timer();
TaskState state = new InitialState();

timer.schedule( new TimerTask() {
     public void run() {
          this.state.run();
          if( shouldChangeState() ) {
              this.state = this.state.next();
           }
     }
 }, 0, 1000 );
Run Code Online (Sandbox Code Playgroud)

最后,如果您需要执行相同的操作,但速度不同,则可以考虑使用TimingFramework.它有点复杂,但让你做一些很酷的动画,允许某些组件的绘画以不同的速率进行(而不是线性)


Dan*_*ark 6

在我看来,这有些误导。如果您的代码需要时间保证,那么您无论如何都不能使用 Timer,也不想使用。“此类不提供实时保证:它使用 Object.wait(long) 方法来安排任务。”

恕我直言,答案是您不想暂停并重新启动计时器。您只是想抑制他们的 run 方法执行他们的业务。这很简单:您只需将它们包含在if声明中即可。开关打开,他们运行,开关关闭,他们错过了那个周期。

编辑:这个问题已经与最初的问题发生了很大的变化,但我会留下这个答案,以防它对任何人有帮助。我的观点是:如果您不关心事件何时在 N 毫秒范围内触发(只是它不会每 N 毫秒超出一次),您可以在 run 方法上使用条件。事实上,这是一种非常常见的情况,尤其是当 N 小于 1 秒时。