我编写了一个方法processMetrics
,如果包含数据的文件自上次请求以来更新,该方法将加载新的度量。我希望该方法每10秒执行一次,因此决定使用ExecutorService
。
但是,当我在使用config。我可以看到,该方法是在执行器没有从静态块加载配置的情况下调用的。当我在没有首先调用注释行的情况下运行测试时,由于没有更新任何配置,它返回false。但是当我运行MetricsProcessor.isMetricValid("Metric_1");
然后运行assertTrue(MetricsProcessor.isMetricValid("Metric_1"))
时;配置被加载,测试返回true。
是什么导致了这种行为?我得出的结论是,这是因为MetricsProcessor
类没有及时加载。这是一个有效的假设吗?
此外,我通过在executor之前的静态块的第一行显式调用processMetrics();
,成功地解决了这个问题。但仍然不清楚为什么会发生这种情况?
@Test
public void testIsMetricValid() {
// MetricsProcessor.isMetricValid("Metric_1");
assertTrue(MetricsProcessor.isMetricValid("Metric_1"));
}
// MetricsProcessor is a final class
private static Runnable loadMetrics = MetricsProcessor::processMetrics;
private static ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
static {
executor.scheduleAtFixedRate(processMetrics, 0, 10, TimeUnit.SECONDS);
}
private static void processMetrics() {
{
long metricsLastMod = metricsFile.lastModified();
if (metricsLastMod > lastMod.get()) {
processMetricsData(metricsFile);
lastMod.set(metricsLastMod);
}
}
您正面临比赛条件。有两个线程:
- 加载类,然后运行测试
- 执行计划任务
在某些情况下,调度程序的启动速度可能比您的测试更快。但这并不能保证。因此,为了防止比赛条件,你需要确保至少第一次执行你的任务。
这是解决方案之一:
private static Runnable loadMetrics = MetricsProcessor::processMetrics;
private static ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
static {
loadMetrics.run();
// Note the updated initial delay.
executor.scheduleAtFixedRate(loadMetrics, 10, 10, TimeUnit.SECONDS);
}