我正在将应用程序使用的JodaTime/Java.utils时间转换为Java 8的时间...我们经常使用Date (这不是线程安全的),所以我没有改变所有这些引用,而是尝试使用Java 8的类并利用它。这是我想出来的:
在测试时,它工作得很好。我们使用的是Spring,有两个ScheduledExecutorTasks (基本上是线程)运行增量任务,并使用此代码的" format“部分将日期格式化为ISO_ZULU格式。
然而,这不起作用。格式化的时间似乎不正确,可能会导致404错误。它很难测试,因为它是我们的QA服务器在运行它,它不是在本地发生的。
我的问题是,我做的是安全的吗?如果不是,是不是因为我使用了Date?使用线程安全类(比如Instant)能解决我的问题吗?
public class DateTimeUtils {
public enum Pattern{
ISO_ZULU("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"),
AMERICAN("MM-dd-yyyy"),
UTC("yyyy-MM-dd'T'HH:mm:ssZ"),
TIME_TRAVEL("yyyy-MM-dd HH:mm:ss"),
MERIDIEM("a"),
HOUR_MINUTES("h:mm"),
MILITARY("HH:mm");
private final String pattern;
Pattern(String pattern){
this.pattern = pattern;
}
public String toString(){
return pattern;
}
}
protected static final Log logger = LogFactory.getLog(DateTimeUtils.class);
private static final String UTC_ZONE_ID = "Etc/UTC";
private static final String DEFAULT_ZONE_ID = ZoneId.systemDefault().getId();
public static String format(Pattern pattern, Date date){
return format(pattern.toString(), date, false);
}
public static String format(Pattern pattern, Date date, boolean arcTimeZone){
return format(pattern.toString(), date, arcTimeZone);
}
public static String format(String pattern, Date date, boolean arcTimeZone){
ZoneId zoneId;
if(arcTimeZone){
zoneId = getTimeZone();
}else{
zoneId = ZoneId.of(UTC_ZONE_ID);
}
return DateTimeFormatter.ofPattern(pattern).withZone(zoneId).format(date.toInstant());
}
}
发布于 2016-12-15 14:13:03
tl;dr
是。你所做的似乎是线程安全的。
详细信息
您在每次调用时都会传入一个对java.util.Date
对象的引用。该引用不会被持有,它会在静态方法调用的末尾消失。所以其他线程都看不到dcsohl注释的那个特定引用。
线程安全是关于共享资源的争用。在这里显示的代码中,您没有共享该Date
引用。您可能会在其他线程上的其他代码中共享它,这可能是一个问题。但考虑到您在这里向我们展示的内容,没有问题。
java.time类使用immutable objects并且是完全线程安全的afaik。所以不用担心这方面的事情。
我不知道LogFactory.getLog
的线程安全性,但这超出了您的问题的范围。
如果传递的Date
在其他线程中的其他代码中使用,您可能会遇到线程安全问题。请阅读下面的内容,以获得不通过Date
的建议。
建议
除了你关于线程安全的问题之外,还有其他一些问题。
调整旧代码,而不是新代码
我建议您将您的论点从Date
改为Instant
。在所有调用代码中,将调用更改为传递myExampleDate.toInstant()
而不是传递myExampleDate
。这使得您的代码更加自我文档化,因为您正在向java.time迁移,而不是遗留的日期-时间类(Date
、Calendar
、SimpleDateFormat
等)。如果这是你的目标,你不想让新代码转向旧的方式,旧的代码应该倾向于新的代码(这样做是低风险/低成本的)。
以java.time如何向旧的遗留类添加新的转换方法为例,就像这里看到的Date.toInstant()
一样。新类对旧的遗留类一无所知。遗留类有责任“跟上程序”。
默认时区
私有静态最终字符串DEFAULT_ZONE_ID = ZoneId.systemDefault().getId();
这条线并不像你想的那样是最终和永久的。当您的代码执行时,JVM的当前默认时区可能会在运行时的任何时刻发生变化。JVM虚拟机中任何应用程序的任何线程中的任何代码都可以随时通过调用TimeZone.setDefault
来更改当前的默认时区。
此外,在Java的必须实现中,JVM在启动时的缺省设置是使用主机操作系统的缺省时区的当前值。这是您无法控制的外部性,因此任何系统管理员都可能无意中改变您的应用程序的行为。时区设置的同上,作为参数传递给JVM的启动脚本。
我建议你放弃这行。相反,请始终在所有代码中传递所需/预期的时区。切勿隐式依赖于JVM的当前默认时区。
当你真的想要当前的默认值时,每次都调用ZoneId.systemDefault()
,以获得最新的事实,而不是一个可能已经过时(不再为真)的缓存值。这也使您的代码更具自我文档化。
UTC常量
私有静态最终字符串UTC_ZONE_ID = "Etc/UTC";
java.time类已经为UTC:ZoneOffset.UTC
提供了一个常量。所以不需要你的常量。
https://stackoverflow.com/questions/41130338
复制相似问题