答案的调查和详细信息在问题的注释中。
我有一个小型 Java 项目,它读取一个时间表并将 Joda-时间间隔放入排序映射(在本例中为 TreeMap)中以供进一步处理。这是通过ScheduledExecutorService完成的:
executor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
try {
doWork();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}, 1, 1, TimeUnit.SECONDS);
然后doWork()
读取文件,创建一些间隔,然后使用此比较器(在映射构造函数中指定)填充映射:
@Override
public int compare(Interval o1, Interval o2) {
return o1.getStart().compareTo(o2.getStart());
}
然后,当插入第一个间隔时,代码在比较器中中断。通常我会认为间隔本身有问题,但是我已经检查了几种可能性,并注意到我迷失了多个奇怪的东西:
- 间隔很好,
o1
和o2
是具有相同长时间戳的有效日期时间。 - 没有例外。线程只是停止工作。
- 当我从 Eclipse 启动应用程序时,一切正常。它仅在启动已部署的版本时中断。通过部署,我的意思是它被打包到一个.jar中并复制到一个共享目录中,这里没有容器。
改变
try { doWork(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); }
自
try { doWork(); } catch (Throwable e) { e.printStackTrace(); throw new RuntimeException(e); }
修复它。(即地图填充得很好,包括原始的第一个间隔)。
最后一部分让我认为这是 JIT 或 JVM 的错误,而不是代码的错误。我还探讨了这是构建问题的可能性,但事实似乎并非如此:
- Eclipse 和构建服务器都使用 Java 7(Eclipse 7.0.51,构建服务器:7.0.25,使用 7.0.51 JRE 启动部署版本)
- Joda 时间库版本在 Eclipse 和部署的 lib 文件夹 (2.1) 中都是相同的
- 这不是一个新功能,相同的代码在不同的分支中工作,并且已经存在了几个星期
- 我尝试阻止 Eclipse 使用自己的缓存 Ivy 库,而是使用已部署目录中的库。同样的东西 - 从Eclipse工作,在使用Java启动jar时不起作用。
经过一些远程调试后,我重现了类似的东西:Method "compareTo" with signature "(Lorg/joda/time/ReadableInstant;)I" is not applicable on this object
在比较器代码中断点时class org.joda.time.DateTime
目标对象。
有关如何进一步调试的任何帮助将不胜感激。
编辑:
private void doWork() {
SortedMap<Interval, String> map = new TreeMap<>(new Comparator<Interval>() {
@Override
public int compare(Interval o1, Interval o2) {
return o1.getStart().compareTo(o2.getStart());
}
});
Collection<String> col1 = new HashSet<>();
Collection<String> col2 = new HashSet<>();
String string = "";
long ts = 0;
try (FileInputStream input = new FileInputStream(fileName);
InputStreamReader isr = new InputStreamReader(input);
BufferedReader reader = new BufferedReader(isr)) {
String line = reader.readLine();
map.put(new Interval(new DateTime(), new DateTime()), "");
}
}
虽然由于大量额外的代码,这看起来不像 SSCCE,但如果我删除集合声明或读取的行,或者在 try 块之前将任何内容放入地图中(然后按原样完成其余部分) - 一切正常。让我想到竞争条件,但是这里涉及的所有变量都是局部的(文件名除外,它保证已经设置)。
此外,在尝试东西时,我发现从 2.3 切换到 Joda-time 2.1 显然可以解决问题。但是,我在他们的错误修复更改日志中没有看到任何看起来甚至远程相关的内容。
根据我的评论,这里有一个总结性的答案:
远程端有第二个JodaTime版本吗?也许是 2.0 版之前的旧版本,其中可比处理发生了一些变化(请参阅通用接口 ReadableInstant)?在 2.0 之前,有问题的方法具有签名compareTo(Object)
而在 2.0 及更高版本中,新的签名compareTo(ReadableInstant)
,另请参阅发行说明。两个 joda-jar 和一个连接的类加载问题的情况将解释以下异常消息:
带有签名"(Lorg/joda/time/ReadableInstant;)I"的方法"compareTo"不适用于此对象,目标对象为类org.joda.time.DateTime
。
(你的问题很棘手,应该得到更多的支持。很高兴听到您在包含较旧的JodaTime版本的JRuby库中找到了原因。