Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 单例线程安全SAX解析器实例_Java_Multithreading_Singleton_Sax - Fatal编程技术网

Java 单例线程安全SAX解析器实例

Java 单例线程安全SAX解析器实例,java,multithreading,singleton,sax,Java,Multithreading,Singleton,Sax,我想创建一个SAX解析器的单例实例,它是线程安全的 但我不能使用随需应变的习惯用法,因为SAX解析器抛出SAXException,如果将其设为类变量,则无法处理该异常。这是我写的代码 public class Parser { private static SAXParser parser; Parser() throws ParserConfigurationException, SAXException { if (parser==null) pars

我想创建一个SAX解析器的单例实例,它是线程安全的

但我不能使用随需应变的习惯用法,因为SAX解析器抛出SAXException,如果将其设为类变量,则无法处理该异常。这是我写的代码

public class Parser {
    private static SAXParser parser;
    Parser() throws ParserConfigurationException, SAXException {
    if (parser==null)
        parser=LazyHolder.factory.newSAXParser();
    }
    private static class LazyHolder {
        private static final SAXParserFactory factory=SAXParserFactory.newInstance();
        }
    public SAXParser getInstance() {
        return parser;
    }
}
有没有更好的方法来实现这一目标

但我不能使用随需应变的习惯用法,因为SAX解析器抛出SAXException,如果将其设为类变量,则无法处理该异常

如果这只是为了在初始化期间绕过异常,则可以通过执行以下操作来绕过异常:

 public class Wrapper {
     private static MyClassThatThrows singleton;
     static {
         try {
             singleton = new MyClassThatThrows();
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
     }
     ...
     public static MyClassThatThrows getInstance() {
        return singleton;
     }
}
当然,如果解析器抛出,这将停止类的加载

但是,
SAXParserFactory
SAXParser
都不是线程安全的,因此您可以使用
ThreadLocal
来为每个线程生成一个线程

public class Parser {
    private final ThreadLocal<SAXParserFactory> factoryThreadLocal = new ThreadLocal<>() {
         public SAXParserFactory initialValue() {
             try {
                 return SAXParserFactory.newInstance();
             } catch (Exception e) {
                 throw new RuntimeException(e);
             }
         }
    };
    public SAXParser getInstance() {
        // you could catch and re-throw the RuntimeException if the caller should handle it
        return factoryThreadLocal.get().newInstance();
    }
}
公共类解析器{
私有最终ThreadLocal factoryThreadLocal=新ThreadLocal(){
公共SAXParserFactory初始值(){
试一试{
返回SAXParserFactory.newInstance();
}捕获(例外e){
抛出新的运行时异常(e);
}
}
};
公共SAXParser getInstance(){
//如果调用方应该处理RuntimeException,您可以捕获并重新抛出它
返回factoryThreadLocal.get().newInstance();
}
}

您认为SAXParser是安全的假设是错误的。请参阅下面的链接

之前我还认为SAXParser是线程安全的,有时我会出现以下错误,当一个线程已经在使用parser对象来解析xml,而另一个线程也试图使用相同的对象时,就会发生这种情况。当我为每个线程创建SAXParser实例时,异常得到了修复


org.xml.sax.SAXException:解析时不能调用FWK005 parse。
在com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1253)~[na:1.8.0\u 20]
在com.sun.org.apache.xerces.internal.jaxp.saxpasserimpl$jaxpsaxpasser.parse(saxpasserimpl.java:649)~[na:1.8.020]
在com.sun.org.apache.xerces.internal.jaxp.saxpasserimpl.parse(saxpasserimpl.java:333)~[na:1.8.020]
在javax.xml.parsers.SAXParser.parse(SAXParser.java:195)~[na:1.8.020]

我不明白这是怎么回事。是否希望几个线程使用相同的SAXParser实例?当一个线程在使用这个实例时,其他线程不能,对吗?不,我希望一个SAXParser实例可以被不同的线程同时使用。真的有可能吗?新的解析器实例有点昂贵。有没有有效的方法可以在多个线程中重用相同的实例。SAXParser不是线程安全的,这就是为什么不同的线程不能同时使用同一个实例。您可以通过几个线程重用一个实例,但不能同时逐个重用。如果您希望通过不同的线程进行并发解析,则必须创建SAXParser实例池。我们还可以为每个线程创建新实例。这也可以正常工作吗?