在B2B(企业对企业)应用中XML扮演一个重要的角色。在这些应用中采用Simple API for XML (SAX)或者document.nbspObject Model (DOM)解析器来解析xml文件。(这两个解析器都是java的api,他们可以在下面的附录中找到)在一个单线程应用中解析是简单明了的。但是,在多线程的应用中这就是很复杂和具有挑战性了,比如说做一个应用服务器,因为应用经常会为解析xml创建一个专门的线程,解析的数据用来为许多同时并发运行的线程服务。这篇文章描述了一个在并发应用中的xml的解析实现。 设计方法 基于并发的生产和消费设计概念,一个专门的线程作为一个生产者去解析xml。一组线程作为消费者,作为解析xml数据的生产线程,他把数据存储在一个共享的数据结构中以供消费线程在将来进行处理时取得,为了最大化产生数据的能力同时最小化内存的使用,这个设计使用了一个特别的队列来分别为生产者、消费者存储和找到解析的数据. 巧妙的队列(Smart Queuing) SmartQueue 队列类提供给生产消费线程们队列的功能,他主要的责任是维护队列防止(线程)超载和断流。换句话说,SmartQueue采用维护一个固定长度的队列的方法去保持资源的应用效率。他挂起和唤醒适当的线程在适当的时候,打个比方,如果没有填充数据的空间,队列将挂起生产线程直到一个消费线程从队列里移去一项。 下面的SmartQueue 代码片断展示了这种策略的实现。 public synchronized void put(Object data) { // check to see if the length is 2 while (list.size() >= 2) { try { System.out.println("Waiting to put data"); wait(); } catch (Exception ex) { } } list.add(data); notifyAll(); } public synchronized Object take() { // wait until there is data to get // come out if the end of file signaled while (list.size() <= 0 && (eof != true)) { try { System.out.println("Waiting to consume data"); wait(); } catch (Exception ex) { } } Object obj = null; if (list.size() > 0) { obj = list.remove(0); } else { System.out.println("Woke up because end of document.quot;); } notifyAll(); return obj; } xml 解析 这个设计使用SAX API来解析XML文件是有以下原因的: 这个API读取 XML数据是快速高效的,他不构造任何内部的XML数据描述,相应的,他在遇到XML元素时简单的把数据传递给应用程序。SAX API十分适合生产-消费模式. xml 解析控制器(XMLParserHandler) 的类继承自SAX,实现回叫(callback )方法从解析器中接收XML数据,当解析控制器类从解析器中接收XML数据时,他把数据put进hashtable里。在每个文档的结尾,解析控制器把数据put进SmartQueue队列里。这个控制器将进入一个等待状态如果SmartQueue队列里有空间,一旦消费线程从SmartQueue队列中移去一项,put方法将被调用。在完成整个XML文档的解析后,解析控制器( XMLParserHandler)通知消费线程停止搜索更多的文档。 让我们看看回叫(callback )方法,他把数据存储入SmartQueue队列然后通知等待的消费线程。起始元素(startElement)方法为每个XML文件中的每个文挡元素示例一个新的Hashtable。 public void startElement( String namespaceURI, String localName, String qName, Attributes atts ) throws SAXException { System.out.println( " startElement local names............." + localName + " " + qName); if (qName.equalsIgnoreCase(elemmark)) { doc = new Hashtable(); } elem = qName; } 结尾元素(endElement)方法负责把解析的数据加到SmartQueue队列中。就象前面提起的,SmartQueue队列挂起这个线程直到没有空间来存储数据。 public void endElement( String namespaceURI, String localName, String qName ) throws SAXException { String s = sbData.toString(); System.out.println("element " + elem + " character " + s); if ((doc != null) & (s != null) & !(s.trim().equals(""))) doc.put(elem, s); sbData = new StringBuffer(); System.out.println(" endElement ending element............." + qName); if (qName.equalsIgnoreCase(elemmark)) { System.out.println( " endElement ending element............." + localName); smartQueue.put(doc); doc = null; } } 最终,结尾文档元素(enddocument.nbsp)回叫方法通知消费线程到达了xml文档的结尾。这意味着消费线程不用去等待其他数据完成他们的工作。 public void enddocument.) throws SAXException { smartQueue.end(); System.out.println("End document...........[1] [2] 下一页
|
|