[java client] make DateFormat safe to use Todd's error-prone patch discovered this problem in RowResult where we use a static DateFormat from multiple threads. The recommended way to do this is to use thread locals.
Change-Id: I6d18ba34db0a0782fd0b7401e9aea7ae59c6b6f6 Reviewed-on: http://gerrit.cloudera.org:8080/4429 Tested-by: Kudu Jenkins Reviewed-by: Adar Dembo <a...@cloudera.com> (cherry picked from commit b0b273e8271752b6eb04ba163981aad1c792e413) Reviewed-on: http://gerrit.cloudera.org:8080/4603 Reviewed-by: Jean-Daniel Cryans <jdcry...@apache.org> Tested-by: Jean-Daniel Cryans <jdcry...@apache.org> Project: http://git-wip-us.apache.org/repos/asf/kudu/repo Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/653ddf3a Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/653ddf3a Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/653ddf3a Branch: refs/heads/branch-1.0.x Commit: 653ddf3aae9787f3e2817af0618cab8882b16857 Parents: 80629bb Author: Jean-Daniel Cryans <jdcry...@apache.org> Authored: Thu Sep 15 16:21:23 2016 -0700 Committer: Jean-Daniel Cryans <jdcry...@apache.org> Committed: Mon Oct 3 21:40:55 2016 +0000 ---------------------------------------------------------------------- .../java/org/apache/kudu/client/RowResult.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/kudu/blob/653ddf3a/java/kudu-client/src/main/java/org/apache/kudu/client/RowResult.java ---------------------------------------------------------------------- diff --git a/java/kudu-client/src/main/java/org/apache/kudu/client/RowResult.java b/java/kudu-client/src/main/java/org/apache/kudu/client/RowResult.java index 0ef3e03..64871d9 100644 --- a/java/kudu-client/src/main/java/org/apache/kudu/client/RowResult.java +++ b/java/kudu-client/src/main/java/org/apache/kudu/client/RowResult.java @@ -39,10 +39,17 @@ import java.util.TimeZone; public class RowResult { private static final int INDEX_RESET_LOCATION = -1; - private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); - static { - DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC")); - } + + // Thread local DateFormat since they're not thread-safe. + private static final ThreadLocal<DateFormat> DATE_FORMAT = new ThreadLocal<DateFormat>(){ + @Override + protected DateFormat initialValue() { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + sdf.setTimeZone(TimeZone.getTimeZone("UTC")); + return sdf; + } + }; + private static final long MS_IN_S = 1000L; private static final long US_IN_S = 1000L * 1000L; private int index = INDEX_RESET_LOCATION; @@ -513,7 +520,7 @@ public class RowResult { long tsMillis = timestamp / MS_IN_S; long tsMicros = timestamp % US_IN_S; StringBuffer formattedTs = new StringBuffer(); - DATE_FORMAT.format(new Date(tsMillis), formattedTs, new FieldPosition(0)); + DATE_FORMAT.get().format(new Date(tsMillis), formattedTs, new FieldPosition(0)); formattedTs.append(String.format(".%06dZ", tsMicros)); return formattedTs.toString(); }