我很难在以下两个实现之间做出决定。 我想缓存每个线程的javax.xml.parsers.DocumentBuilder对象。我主要担心的是运行时性能--Hench我很乐意避免使用尽可能多的GC。记忆不是问题。
我已经写了两个POC实现,很高兴听到社群PROS / CONS关于每个实现。
感谢帮助人员。
import java.io.IOException;
import java.io.StringReader;
import java.util.WeakHashMap;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class DocumentBuilder_WeakHashMap {
private static final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
private static final WeakHashMap<Thread, DocumentBuilder> CACHE = new WeakHashMap<Thread, DocumentBuilder>();
public static Document documentFromXMLString(String xml) throws SAXException, IOException, ParserConfigurationException {
DocumentBuilder builder = CACHE.get(Thread.currentThread());
if(builder == null) {
builder = factory.newDocumentBuilder();
CACHE.put(Thread.currentThread(), builder);
}
return builder.parse(new InputSource(new StringReader(xml)));
}
}
import java.io.IOException;
import java.io.StringReader;
import java.lang.ref.WeakReference;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class DocumentBuilder_ThreadLocal {
private static final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
private static final ThreadLocal<WeakReference<DocumentBuilder>> CACHE =
new ThreadLocal<WeakReference<DocumentBuilder>>() {
@Override
protected WeakReference<DocumentBuilder> initialValue() {
try {
return new WeakReference<DocumentBuilder>(factory.newDocumentBuilder());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
public static Document documentFromXMLString(String xml) throws ParserConfigurationException, SAXException, IOException {
WeakReference<DocumentBuilder> builderWeakReference = CACHE.get();
DocumentBuilder builder = builderWeakReference.get();
if(builder == null) {
builder = factory.newDocumentBuilder();
CACHE.set(new WeakReference<DocumentBuilder>(builder));
}
return builder.parse(new InputSource(new StringReader(xml)));
}
}
他们都做同样的事情(将documentFromXMLString()暴露给外界),你会使用哪一个?
谢谢你, 格言。
答案 0 :(得分:6)
只要您不使用弱引用,而是直接使用ThreadLocal<DocumentBuilder>
,ThreadLocal解决方案就更好了。
对ThreadLocal值的访问更快,因为线程直接引用包含所有ThreadLocal值的数组,并且它只需要计算此数组中的索引以进行查找。
查看ThreadLocal source以了解索引计算速度快的原因(int index = hash & values.mask;
)
答案 1 :(得分:4)
小心!
ThreadLocal
将保留对DocumentBuilder
的无限引用,其中包含对该线程DocumentBuilder
解析的最新XML文档的引用。
这有几个后果,可能被认为是内存泄漏:
xmlparser2.jar
),则保留对DocumentBuilder
的引用将导致Web应用程序的所有类在取消部署时泄漏,最终导致OutOfMemoryError
:PermGenSpace! (谷歌周围有关此主题的更多信息)DocumentBuilder
解析的最新XML文档很大,它将继续占用内存,直到在该线程上解析新的XML文档。如果在线程池中有长时间运行的线程(例如在J2EE容器中),这可能是一个问题,尤其是在需要解析大量大型文档时。是的,最终将释放内存,但在此之前可能会耗尽可用内存,并且GC在DocumentBuilder
引用时将无法清理XML文档存在。决定这是否与您相关......
答案 2 :(得分:3)
单独的WeakHashMap将失败,因为它不是线程安全的:
“与大多数集合类一样,此类不同步。”
(JavaDoc)的第3段
由于同步需要花费时间而Collections.synchronizedMap
无法很好地扩展,因此您应该坚持使用ThreadLocal
。