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
请注意,从重复计时器任务的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)
如果您已经取消了一个计时器,则无法重新启动它,您必须创建一个新计时器.
看到这个答案,它包含一个视频和源代码我是如何做类似的事情的.
基本上有两种方法:pause和resume
暂停时:
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.它有点复杂,但让你做一些很酷的动画,允许某些组件的绘画以不同的速率进行(而不是线性)
在我看来,这有些误导。如果您的代码需要时间保证,那么您无论如何都不能使用 Timer,也不想使用。“此类不提供实时保证:它使用 Object.wait(long) 方法来安排任务。”
恕我直言,答案是您不想暂停并重新启动计时器。您只是想抑制他们的 run 方法执行他们的业务。这很简单:您只需将它们包含在if声明中即可。开关打开,他们运行,开关关闭,他们错过了那个周期。
编辑:这个问题已经与最初的问题发生了很大的变化,但我会留下这个答案,以防它对任何人有帮助。我的观点是:如果您不关心事件何时在 N 毫秒范围内触发(只是它不会每 N 毫秒超出一次),您可以在 run 方法上使用条件。事实上,这是一种非常常见的情况,尤其是当 N 小于 1 秒时。