我有一个关于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();
}
}
所以我的问题是,在timer1
运行时,如何在运行timer2
时暂停timer2
,反之亦然?性能和时间是我的主要关注点,因为这需要在另一个正在运行的线程中实现。顺便说一句,我试图在Android上实现这些并发计时器。
感谢您的帮助!
答案 0 :(得分:25)
请注意,从中调用此方法 在重复的运行方法中 计时器任务绝对保证 计时器任务不会再次运行。
因此,一旦取消,它将永远不会再次运行。你最好使用更现代的ScheduledExecutorService
(来自Java 5 +)。
编辑:基本构造是:
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(runnable, 0, 1000, TimeUnit.MILLISECONDS);
但是调查一下,没有办法在没有关闭服务的情况下取消该任务,这有点奇怪。
在这种情况下, 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);
答案 1 :(得分:15)
我找到的最简单的解决方案:只需在计时器任务的运行代码中添加一个布尔值,如下所示:
timer.schedule( new TimerTask() {
public void run() {
if(!paused){
//do your thing
}
}
}, 0, 1000 );
答案 2 :(得分:6)
如果您已取消一个计时器,则无法重新启动它,您必须创建一个新计时器。
请参阅此answer,它包含一个视频和源代码我是如何做类似的事情。
基本上有两种方法:pause
和resume
暂停:
public void pause() {
this.timer.cancel();
}
简历中:
public void resume() {
this.timer = new Timer();
this.timer.schedule( aTask, 0, 1000 );
}
这让人感觉暂停/恢复。
如果您的计时器根据应用程序的状态执行不同的操作,您可以考虑使用StatePattern
拳头定义一个抽象状态:
abstract class TaskState {
public void run();
public TaskState next();
}
并提供任意数量的州。关键是一个州引导你到另一个州。
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();
}
}
然后你改变计时器中的状态。
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 );
最后,如果您需要的是执行相同的操作,但速度不同,您可以考虑使用TimingFramework。它有点复杂,但让你做一些很酷的动画,允许某些组件的绘画以不同的速率进行(而不是线性)
答案 3 :(得分:4)
查看您的源代码,以下是更改(这几乎验证了我以前的答案)
在task1中:
// Stop timer1 and start timer2
timer1.cancel();
timer2 = new Timer(); // <-- just insert this line
timer2.scheduleAtFixedRate(new Task2(), 0, 1000);
并在任务2中:
// Stop timer2 and start timer1
timer2.cancel();
timer1 = new Timer(); // <-- just insert this other
timer1.scheduleAtFixedRate(new Task1(), 0, 1000);
它在我的机器上运行:
it works! http://img687.imageshack.us/img687/9954/capturadepantalla201001m.png
答案 4 :(得分:4)
在我看来,这有点误导。如果你的代码需要时间保证,你无论如何也不能使用Timer,也不想。 “这个类不提供实时保证:它使用Object.wait(long)方法调度任务。”
答案,恕我直言,你不想暂停和重启你的计时器。你只想抑制他们的运行方法来开展业务。这很容易:你只需将它们包装在if
语句中即可。开关打开,它们运行,开关关闭,它们错过了那个循环。
编辑:这个问题已经从最初的问题发生了很大变化,但我会留下这个答案以防万一它能帮到任何人。我的观点是:如果您不关心事件是否在N毫秒范围内触发(只是每N毫秒没有超出一次),您可以在运行方法上使用条件。事实上,这是一种非常常见的情况,特别是当N小于1秒时。
答案 5 :(得分:3)
Android不会重复使用已经安排过一次的TimerTask。因此,有必要重新实现Timer和TimerTask,例如片段中的这样:
private Timer timer;
private TimerTask timerTask;
public void onResume ()
{
super.onResume();
timer = new Timer();
timerTask = new MyTimerTask();
timer.schedule(timerTask, 0, 1000);
}
public void onPause ()
{
super.onPause();
timer.cancel(); // Renders Timer unusable for further schedule() calls.
}
答案 6 :(得分:0)
我可以使用以下代码停止计时器和任务:
if(null != timer)
{
timer.cancel();
Log.i(LOG_TAG,"Number of cancelled tasks purged: " + timer.purge());
timer = null;
}
if(task != null)
{
Log.i(LOG_TAG,"Tracking cancellation status: " + task.cancel());
task = null;
}
答案 7 :(得分:0)
Timer timer1;
private boolean videoCompleteCDR=false;
private boolean isVideoPlaying=false;
int videoTime=0;
private int DEFAULT_VIDEO_PLAY_TIME = 30;
@Override
public View onCreate(){
isVideoPlaying = true; //when server response is successfully
}
@Override
public void onPause() {
super.onPause();
if(isVideoPlaying ) {
if(this.timer1 !=null) {
this.timer1.cancel();
}
}
}
@Override
public void onResume() {
super.onResume();
if(isVideoPlaying && !videoCompleteCDR) {
callTimerTask();
}
}
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if (!hidden) {
printLog( "GameFragment visible ");
if(isVideoPlaying && !videoCompleteCDR) {
callTimerTask();
}
} else {
printLog("GameFragment in visible ");
if(isVideoPlaying) {
if(this.timer1 !=null) {
this.timer1.cancel();
}
}
}
}
private void callTimerTask() {
// TODO Timer for auto sliding
printLog( "callTimerTask Start" );
timer1 = new Timer();
timer1.schedule(new TimerTask() {
@Override
public void run() {
if (getActivity() != null) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if (getActivity() == null) {
return;
}
videoTime++;
if(DEFAULT_VIDEO_PLAY_TIME ==videoTime){
videoCompleteCDR=true;
Log.e("KeshavTimer", "callTimerTask videoCompleteCDR called.... " +videoTime);
destroyTimer();
}
Log.e("KeshavTimer", "callTimerTask videoTime " +videoTime);
}
});
} else {
printLog("callTimerTask getActivity is null ");
}
}
}, 1000, 1000);
// TODO 300, 2000;
}
private void destroyTimer(){
this.timer1.cancel();
}