这就是问题所在。我有以下抽象类。
public abstract class JAXBParser<T> {
private static final Object lock = new Object();
private static volatile JAXBContext context;
private JAXBContext getContext() {
if (context == null) {
synchronized (getClass()) {
if (context == null) {
try {
context = JAXBContext.newInstance(getJAXBClass());
} catch (JAXBException e) {
log.error("Couldn't create JAXB context", e);
}
}
}
}
return context;
}
@SuppressWarnings("unchecked")
public Optional<T> parse(File file) {
log.debug(file.getAbsolutePath());
try {
JAXBContext context = getContext();
Unmarshaller unmarshaller = context.createUnmarshaller();
return Optional.ofNullable((T) unmarshaller.unmarshal(file));
} catch (JAXBException e) {
log.error(unmarshallerError(file.getAbsolutePath()), e);
}
return Optional.empty();
}
protected abstract Class getJAXBClass();
}
这个想法是,我将有几个解析器具有相同的行为,因此我可以使用它来遵循DRY原理(以及继承,多线程,同步等)。同样在this问题中,JAXBContext初始化很繁重,因此最好将其初始化一次。因此,我决定使用双重检查锁定对每个子类进行一次初始化。
问题如下:
使用getClass()进行同步是否是个坏主意?使用锁对象会更好,为什么?
答案 0 :(得分:2)
Class
的实例也是Object
,对其进行同步完全有效。
但是,由于只有一个实例,因此如果将来需要多个实例,您将无法区分不同的(不相关的)同步部分。
这也是声明方法synchronized
的问题-它们不仅在自身上进行同步,而且还在所有同级上以及可能在对象上进行同步的所有其他外部代码上进行同步,这并不总是显而易见的。 / p>
答案 1 :(得分:1)
锁定公开可见的对象有一个大问题:您不能孤立地推断类的行为。
原因是代码的其他部分也可能选择在类对象上进行同步,从而可能导致getContext()
方法无限期地阻塞。
现在,正如您可能想像的那样,在实践中这很少是一个问题 * 。但是,无论何时(有时是),这都是调试和识别的绝对噩梦。因此,考虑到定义一个私有锁对象并对其进行同步有多么容易,我会考虑使用它。
* 假设没有恶意代码。如果确实愿意,可以通过同步我创建的this example这样不经意间共享的对象来做真正令人讨厌的事情,该对象“无形地”连接输入流和输出流。