【发布时间】:2015-10-29 02:03:15
【问题描述】:
我在一个类中有两个共享可变对象,其线程安全策略已被定义为“线程安全”。
public static final GregorianCalendar CAL = new GregorianCalendar();
public static final SimpleDateFormat SDF = new SimpleDateFormat();
目的是减少对象创建的数量,因为这些对象的创建成本很高,并且需要使用它们的方法预计会被频繁调用。
这是一种这样的(静态工厂)方法:
public static MJD ofTimeStampInZone(String stamp, String form, TimeZone tz) {
double result;
synchronized(lockCal) {
synchronized(lockSdf) {
CAL.setTimeZone(tz);
SDF.setCalendar(CAL);
SDF.applyPattern(form);
try {
Date d = SDF.parse(stamp);
CAL.setTime(d);
result = (CAL.getTimeInMillis() / (86400.0 * 1000.0)) +
POSIX_EPOCH_AS_MJD;
}
catch (ParseException e)
{ throw new IllegalArgumentException("Invalid parsing format"); }
}
}
return new MJD(result);
}
我还为此类设置了一个策略,即必须始终在lockSdf 之前获取lockCal。然而,这个类也是如此:
- 可以在没有 SDF 的情况下锁定和使用 CAL,在这种情况下,SDF 不会被锁定。
- 除非同时使用 CAL,否则绝不会在方法中使用 SDF
因为 SDF 依赖于 CAL,我想知道单独锁定 lockCal 是否足以防止并发访问期间的数据不一致。这将允许我免除对 SDF 的锁定。换句话说,如果我只使用上述条件,线程安全是否仍然得到保证:
public static MJD ofTimeStampInZone(String stamp, String form, TimeZone tz) {
double result;
synchronized(lockCal) {
CAL.setTimeZone(tz);
SDF.setCalendar(CAL);
SDF.applyPattern(form);
try {
Date d = SDF.parse(stamp);
CAL.setTime(d);
result = (CAL.getTimeInMillis() / (86400.0 * 1000.0)) +
POSIX_EPOCH_AS_MJD;
}
catch (ParseException e)
{ throw new IllegalArgumentException("Invalid parsing format"); }
}
return new MJD(result);
}
【问题讨论】:
-
您还有其他代码在
lockCal和lockSdf上使用双重锁定吗? -
是的,我还有另外两种方法可以锁定
lockCal,然后锁定lockSdf。我有几种方法只锁定lockCal,但这些方法不会改变SDF的状态 -
请贴出相关代码sn-ps。您不需要向我们展示所有内容,只需类似于您向我们展示的内容
ofTimeStampInZone -
其线程安全策略已被定义为“线程安全”。 - 但这些类不是线程安全的:stackoverflow.com/questions/12131324/… 和 docs.oracle.com/javase/7/docs/api/java/text/…
-
@Ruslan:不要求线程安全的类不能由本身不是线程安全的组件组成(实际上,线程安全的类是由可变的、非线程的安全类(例如 ArrayList)一直)。
标签: java concurrency synchronization thread-safety