Java-为什么静态块中的方法没有及时加载?

时间:2018-11-12 07:37:00

标签: java multithreading testing java-8 race-condition

我编写了一种方法processMetrics,如果包含数据的文件自上次请求以来已更新,则该方法将加载新指标。我希望该方法每10秒执行一次,因此决定为此目的使用ExecutorService

但是,当我从使用config的类中测试方法时。我可以看到在没有执行者从静态块加载配置的情况下调用了该方法。 当我在不首先调用注释行的情况下运行测试时,由于未更新任何配置,它会返回false。 但是当我先运行MetricsProcessor.isMetricValid("Metric_1");然后运行assertTrue(MetricsProcessor.isMetricValid("Metric_1"))时;配置已加载,测试返回true。

什么可能导致这种行为?我得出一个结论,这是因为MetricsProcessor类没有及时加载。这是一个有效的假设吗?

此外,我设法通过在执行程序之前的静态块第一行中显式调用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);
            }
}

1 个答案:

答案 0 :(得分:1)

您正面临比赛条件。有两个线程:

  • 加载课程,然后运行测试
  • 执行预定任务

在某些情况下,调度程序的启动速度可能比您的测试更快。但是并不能保证。因此,为了防止出现竞争状况,您需要至少确保首次执行任务。

这是解决方案之一:

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);
}