Which implementation is better: a cache based on WeakHashMap or a cache based on ThreadLocal?

It is difficult for me to solve the following two implementations. I want to cache the javax.xml.parsers.DocumentBuilder object for each thread. My main concern is runtime performance - Hench. I would be happy to avoid as much GC as possible. Memory is not a problem.

I have written two POC implementations and will be glad to hear from the PROS / CONS community regarding each of them.

Thanks for helping the guys.

Option No. 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)));
    }

}

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

They both do the same (expose documentFromXMLString () to the outside world), and which one would you use?

Thank you, Maxim.

+3
3

ThreadLocal , weakreference, ThreadLocal<DocumentBuilder>. ThreadLocal , , ThreadLocal, . ThreadLocal , , (int index = hash & values.mask;)

+6

BEWARE!

ThreadLocal DocumentBuilder, XML-, DocumentBuilder.

, :

  • JAXP - (, Xerces Oracle xmlparser2.jar), DocumentBuilder - , OutOfMemoryError: PermGenSpace! (Google )
  • XML-, DocumentBuilder, , , XML- . (, J2EE), , . , , , , GC XML-, DocumentBuilder.

, ...

+4

Only for WeakHashMap will fail, because it is not thread safe:
"As with most collection classes, this class is not synchronized."
(3rd paragraph in JavaDoc )

Since synchronization will take time, and Collections.synchronizedMapwill not scale very well, you should stick ThreadLocal.

+3
source

Source: https://habr.com/ru/post/1752252/


All Articles