diff --git a/src/main/java/net/fortuna/ical4j/model/DateTime.java b/src/main/java/net/fortuna/ical4j/model/DateTime.java index be4d41aec..43e07b66f 100644 --- a/src/main/java/net/fortuna/ical4j/model/DateTime.java +++ b/src/main/java/net/fortuna/ical4j/model/DateTime.java @@ -39,6 +39,7 @@ import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Collections; import java.util.Map; import java.util.WeakHashMap; @@ -519,9 +520,20 @@ public int hashCode() { return super.hashCode(); } + /** + * This cache class is a workaround for DateFormat not being threadsafe. + * We maintain map from Thread to DateFormat instance so that the instances + * are not shared between threads (effectively a ThreadLocal). + * TODO: once the project targets Java 8+, the new date utilities are + * thread-safe and we should remove this code. + */ private static class DateFormatCache { - private final Map threadMap = new WeakHashMap(); + /** + * This map needs to keep weak references (to avoid memory leaks - see r1.37) + * and be thread-safe (since it may be concurrently modified in get() below). + */ + private final Map threadMap = Collections.synchronizedMap(new WeakHashMap()); private final DateFormat templateFormat; @@ -529,7 +541,7 @@ private DateFormatCache(DateFormat dateFormat) { this.templateFormat = dateFormat; } - public synchronized DateFormat get() { + public DateFormat get() { DateFormat dateFormat = threadMap.get(Thread.currentThread()); if (dateFormat == null) { dateFormat = (DateFormat) templateFormat.clone();