我需要替换java.util.Timer或java.util.concurrent.ScheduledExecutorService,它接受一个时间源,以便可以驱逐系统时间或其他一些引用。我使用这个计时器来定期执行一个方法,但是当应用程序处于“实时”模式时需要周期由系统时间驱动,而当应用程序处于“回放”模式时需要一些其他源。
我确实看到有一些第三方库,例如番石榴秒表,其功能与我的要求类似,但由于我正在处理的信息系统的政策,我更喜欢Java原生的东西。
我可能最终必须写自己的,但我在这里问,因为这似乎是许多人需要的......当使用具有时间段的替代概念的应用程序或用于测试具有嵌入式计时器的单元时
答案 0 :(得分:2)
您可以通过执行以下操作,使用自定义时间源实施java.util.concurrent.ScheduledExecutorService
:
计算自定义时间源和系统时间之间的偏移量或增量(初始化时),并保持ScheduledExecutorService
实现中的增量。当调用schedule
(以及接口中的类似方法)时,使用您在初始化时计算的相同偏移量,并在提供的TimeUnits
上应用这些偏移量。这样 - 您可以依赖调度程序的现有实现。
答案 1 :(得分:0)
如果其他人需要它,这里是我最终的解决方案。
public interface TimeSource {
long currentTimeMillis();
}
public class AlternateTimeSource implements TimeSource {
long currentTime = 0;
public AlternateTimeSource() {
}
public setTime(long time) {
if (time > currentTime) currentTime = time;
}
@Override
public long currentTimeMillis() {
return currentTime;
}
}
public class SystemTimeSource implements TimeSource {
@Override
public long currentTimeMillis() {
return System.currentTimeMillis();
}
}
class SourcedTimerThread extends Thread {
TimeSource reference_;
TimerTask task_;
long period_;
long executionTime_;
boolean done = false;
SourcedTimerThread(TimeSource reference,TimerTask task,long delay,long period) {
reference_ = reference;
task_ = task;
period_ = period >= 0 ? period : 0;
executionTime_ = reference_.currentTimeMillis() + (delay >= 0 ? delay : 0);
setName("SourcedTimerThread_"+reference_.getClass().getSimpleName());
start();
}
public void cancel() {
done = true;
interrupt();
}
public void run() {
long currentTime;
while (!done) {
try {
currentTime = reference_.currentTimeMillis();
if (executionTime_>currentTime) {
// Task hasn't yet fired; wait
sleep(1); }
else {
task_.run();
if (period_ > 0) {
// Repeating task, reschedule
executionTime_ = ((period_ < 0) ? currentTime-period_ : executionTime_ + period_);
}
else {
// Non-repeating task, done
break;
}
}
} catch (InterruptedException e) {
}
}
}
}
用法:
// Build source
TimeSource source = null;
if (alternate) {
source = new AlternateTimeSource();
}
else {
source = new SystemTimeSource();
}
// Configure timer
SourcedTimerThread t = new SourcedTimerThread(source,new TimerTask() {
@Override
void run() {
System.out.println("Yay!");
}
}, delayMs, periodMs);
// Drive timer if necessary
if (alternate) {
// Drive timer based on alternate source such as data
source.setTime(dataRecord.getTime());
}
// When ready to cleanup
t.cancel();