[英]Is nesting of locks necessary for this code?
我在类中有两个共享的可变对象,其线程安全策略已被定义为“线程安全”。
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);
}
我还为这个类设置了一个策略,即在lockCal
之前必须始终获取lockSdf
。 然而,这个类也是如此:
因为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);
}
如果SDF
仅被已获取lockCal
的线程使用,则它一次只能由一个线程访问,即使您在lockSdf
上移除锁定它也是线程安全的。
如果您选择依赖此观察,则应该清楚地记录,以便将来的维护程序员不会在synchronized (lockCal)
之外开始使用SDF
。
一般来说,这里不保证线程安全。 假设SDF应该被lockSDF保护,但是它在不同的锁下被修改,如果它只获取了lockSDF,则另一个线程可能看不到SDF更改的结果。 但是你有一个策略:在lockSdf之前获取lockCal。 看起来它“有点”解决了这个问题,但是
1)它对线程安全的推理太难了
2)它使lockSdf无用
假设SDF依赖于CAL并且CAL由lockCal保护,那么使用lockCal来保护SDF也是有意义的。
Java Concurrency in Practice(Brian Goetz):
第1部分摘要
...
使用相同的锁保护不变量中的所有变量。
...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.