我需要每次都创建DocumentBuilderFactory吗?

4

我需要从RSS源每5分钟更新一次新闻。

我已经编写了一个TimerTask,如下所示:

public class TimerTaskForAllNews 
{
    public static void main( String[] args )
    {
        TimerTask task = new AllNewsUpdatrUtility();
        Timer timer = new Timer();
        timer.schedule(task, 1000,60000);
    }
}

这是我的计时器任务实现类。
package com.util;
import java.net.URL;
public class AllNewsUpdatrUtility extends TimerTask {
      private static AllNewsUpdatrUtility instance = null;
       public AllNewsUpdatrUtility() {}
       public static AllNewsUpdatrUtility getInstance() {
          if (instance == null)
             instance = new AllNewsUpdatrUtility();
          return instance;
       }
    @Override
    public void run() {
         try {
             JSONArray latestnews = new JSONArray();
             JSONObject jsonobj_allnews = new JSONObject();
             DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
             URL url = new URL("http://www.rssmix.com/u/8160628/rss.xml");
             Document doc = builder.parse(url.openStream());
             NodeList items = doc.getElementsByTagName("item");
            for (int i = 0; i < items.getLength(); i++) {
                Element item = (Element) items.item(i);
                String title = getValue(item, "title");
                String link = getValue(item, "link");
                String pub_date = getValue(item, "pubDate");

            } // for loop ends here 

          } catch (Exception e) {
             e.printStackTrace();
          }
    }


}

请问我如何改进这个程序呢?


DBF 不是线程安全的。如果您可以保证它只被一个线程使用,那么可以对其进行缓存。 - qqilihq
1
但是newDocumentBuilder()应该是线程安全的:https://jaxp.java.net/docs/spec/html/#plugabililty-thread-safety。因此,可以创建一个DBF并重复使用它来创建文档构建器的多个线程。 - JB Nizet
那又怎样?newDocumentBuilder()不是一个setter方法。它不会配置工厂。因此,您可以创建一个工厂并从一个线程中进行配置,然后发布它,以便任何线程都可以同时调用其newDocumentBuilder()方法,因为newDocumentBuilder()是线程安全的。 - JB Nizet
1个回答

3
规范 JSR 206 Java™ API for XML Processing (JAXP) 1.4 指出:

预期 SAXParserFactory 实现的 newSAXParser 方法、DocumentBuilderFactory 的 newDocumentBuilder 方法和 TransformerFactory 的 newTransformer 方法都是线程安全且无副作用的。

如评论中所述,您可以缓存 DocumentBuilderFactory 实例:

package com.util;
import java.net.URL;
public class AllNewsUpdatrUtility extends TimerTask {
       private static AllNewsUpdatrUtility instance;
       private final DocumentBuilderFactory dbf;
       private AllNewsUpdatrUtility() {}
       public synchronized static AllNewsUpdatrUtility getInstance() {
          if (instance == null)
             instance = new AllNewsUpdatrUtility();
             dbf = DocumentBuilderFactory.newInstance();
          return instance;
       }
    @Override
    public void run() {
         try {
             JSONArray latestnews = new JSONArray();
             JSONObject jsonobj_allnews = new JSONObject();
             DocumentBuilder builder = dbf.newDocumentBuilder();
             URL url = new URL("http://www.rssmix.com/u/8160628/rss.xml");
             Document doc = builder.parse(url.openStream());
             NodeList items = doc.getElementsByTagName("item");
            for (int i = 0; i < items.getLength(); i++) {
                Element item = (Element) items.item(i);
                String title = getValue(item, "title");
                String link = getValue(item, "link");
                String pub_date = getValue(item, "pubDate");

            } // for loop ends here 

          } catch (Exception e) {
             e.printStackTrace();
          }
    }


}

这远非线程安全:构造函数应该是私有的,dbf不应该是静态的:它应该是final并在构造函数中初始化,getInstance()方法应该是同步的。 - JB Nizet
@JBNizet,楼主并没有要求线程安全的类,但您说得很对。我已经包含了您的建议。 - Ortomala Lokni

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接