哪种实现更好:基于WeakHashMap的缓存还是基于ThreadLocal的缓存?

Max*_*ler 3 java performance multithreading caching

我很难在以下两个实现之间做出决定.我想缓存每个线程的javax.xml.parsers.DocumentBuilder对象.我主要担心的是运行时性能--Hench我很乐意避免使用尽可能多的GC.记忆不是问题.

我已经写了两个POC实现,很高兴听到社区PROS/CONS关于每个实现.

谢谢你的帮助.

选项#1 - WeakHashMap

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)));
    }

}
Run Code Online (Sandbox Code Playgroud)

选项#2 - ThreadLocal

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)));
    }
}
Run Code Online (Sandbox Code Playgroud)

它们都做同样的事情(将documentFromXMLString()暴露给外部世界),你会使用哪一个?

谢谢你,马克西姆.

pgr*_*ras 6

只要你不使用弱引用而是直接使用a,ThreadLocal解决方案就更好了ThreadLocal<DocumentBuilder>.对ThreadLocal值的访问更快,因为线程直接引用包含所有ThreadLocal值的数组,并且它只需要计算此数组中的索引以进行查找.查看ThreadLocal 以查看索引计算为何快速(int index = hash & values.mask;)