2016-09-23 34 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]