The investigation and details for the accepted answer are in the comments to the question.
I have a small Java project that reads a schedule and puts Joda-Time Intervals into a sorted map (TreeMap in this case) for further processing. This is done via a 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()
then reads a file, creates some intervals and then populates the map using this comparator (specified in the map constructor):
@Override
public int compare(Interval o1, Interval o2) {
return o1.getStart().compareTo(o2.getStart());
}
The code then breaks in the comparator when inserting the very first interval. Usually I would think there is something wrong with the interval itself, however I have checked several possibilities and noticed multiple odd things that I got lost in:
- The interval is fine,
o1
ando2
are valid DateTimes with the same long timestamp. - No exception is caught. The thread just ceases work.
- When I launch the app from Eclipse, everything works fine. It only breaks when launching a deployed version. By deployed I mean it was packed into a .jar and copied over to a shared directory, no containers here.
Changing
try { doWork(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); }
to
try { doWork(); } catch (Throwable e) { e.printStackTrace(); throw new RuntimeException(e); }
fixes it. (I.e. map gets populated fine, including the original first interval).
The last part makes me think it is a bug with JIT or JVM, rather than with the code. I have also explored the possibility of this being a build issue, however it does not seem to be the case:
- Both Eclipse and the build server use Java 7 (Eclipse 7.0.51, Build server: 7.0.25, Launched the deployed version with a 7.0.51 JRE)
- Joda time library version is the same both in Eclipse and deployed lib folder (2.1)
- This is NOT a new feature and the very same code works in a different branch, and has been for a couple of weeks now
- I have tried stopping Eclipse from using its own cached Ivy libraries, and instead use the libraries in the deployed directory. Same stuff - works from Eclipse, doesn't work when launching jar with Java.
After a bit of remote-debugging I have reproduced something of the like: Method "compareTo" with signature "(Lorg/joda/time/ReadableInstant;)I" is not applicable on this object
with the target object being class org.joda.time.DateTime
when breakpointing in the comparator code.
Any help in how to debug this further would be appreciated.
EDIT:
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()), "");
}
}
While this does not look like an SSCCE due to a lot of extra code, if I remove the Collection declarations or the line read, or put anything in the map before the try block (and then do the rest as is) - everything works fine. Makes me think of race conditions, however all variables involved here are local (except fileName, which is guaranteed to have been set).
Also, while trying out stuff I found that switching to Joda-time 2.3 from 2.1 apparently fixes the problem. However I do not see anything in their changelog of bugfixes that looks even remotely relevant.