2016-09-23 83 views
1

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

但是我不能使用按需语言,因为SAX解析器会抛出SAXException,如果它被创建为类变量,则无法处理该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; 
    } 
} 

有没有更好的实现方法?

+0

我不明白这应该如何工作。你想要几个线程使用相同的SAXParser实例吗?当一个线程使用这个实例时,其他线程不能,对吗? –

+0

不,我希望像单个SAXParser实例可以被不同的线程同时使用。真的有可能吗? –

+0

解析器的新实例有点贵。是否有任何有效的方法在多个线程中重用相同的实例。我在理解它时遇到了问题。 –

回答

1

但是我不能使用按需成语,因为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; 
    } 
} 

从如果解析器加载停止类抛出当然。

但是,SAXParserFactorySAXParser都不是线程安全的,因此您可以改为使用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(); 
    } 
} 
2

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

https://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/1.5/api/javax/xml/parsers/SAXParserFactory.html

早些时候,我也是在印象中的SAXParser是线程安全的,有时我用得到下面的错误,这是当一个线程已经在使用的解析器对象解析XML发生,同时其他线程也试图使用相同的对象。当我为每个线程创建SAXParser实例时,异常得到解决。

org.xml.sax.SAXException: FWK005 parse may not be called while parsing. at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1253) ~[na:1.8.0_20] at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:649) ~[na:1.8.0_20] at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl.parse(SAXParserImpl.java:333) ~[na:1.8.0_20] at javax.xml.parsers.SAXParser.parse(SAXParser.java:195) ~[na:1.8.0_20]