我正在处理这个程序,它应该使用第一个线程反序列化XML中的对象,并通过管道将其流式传输到第二个线程,然后将其排序并输出结果。Java管道同步
事情是我运行时得到异常,说读写结束都死了。 虽然我尝试调试,但它工作正常,这使我认为这是因为错误的同步。令人困惑的是,因为我认为管道应该处理这个方面。任何人都可以帮我弄清楚我做错了什么,并指出我在正确的方向吗?
下面是可运行的代码: (相关部分是接近尾声)
package domAPI;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class ParserRunnable implements Runnable {
List<Employee> myEmpls;
Document dom;
PipedInputStream pin;
PipedOutputStream pout;
ObjectInputStream in;
ObjectOutputStream out;
int threadNr;
// private final Object sending = new Object();
// private final Object receiving = new Object();
public ParserRunnable(){
myEmpls = new ArrayList<Employee>();
}
public ParserRunnable(PipedOutputStream ws, int threadNr){
myEmpls = new ArrayList<Employee>();
pout = ws;
try {
out = new ObjectOutputStream(pout);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.threadNr = threadNr;
}
public ParserRunnable(PipedInputStream rs, int ThreadNr){
myEmpls = new ArrayList<Employee>();
pin = rs;
try {
in = new ObjectInputStream(pin);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.threadNr = threadNr;
}
private void parseXmlFile(){
//get the factory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
//Using factory get an instance of document builder
DocumentBuilder db = dbf.newDocumentBuilder();
//parse using builder to get DOM representation of the XML file
dom = db.parse("persons.xml");
}catch(ParserConfigurationException pce) {
pce.printStackTrace();
}catch(SAXException se) {
se.printStackTrace();
}catch(IOException ioe) {
ioe.printStackTrace();
}
}
private void parseDocument(){
//get the root element
Element docEle = dom.getDocumentElement();
//get a nodelist of <employee> elements
NodeList nl = docEle.getElementsByTagName("Employee");
if(nl != null && nl.getLength() > 0) {
for(int i = 0 ; i < nl.getLength();i++) {
//get the employee element
Element el = (Element)nl.item(i);
//get the Employee object
Employee e = getEmployee(el);
//add it to list
myEmpls.add(e);
}
}
}
/**
* I take an employee element and read the values in, create
* an Employee object and return it
* @param empEl
* @return
*/
private Employee getEmployee(Element empEl) {
//for each <employee> element get text or int values of
//name ,id, age and name
String name = getTextValue(empEl,"Name");
int id = getIntValue(empEl,"Id");
int age = getIntValue(empEl,"Age");
String type = empEl.getAttribute("type");
//Create a new Employee with the value read from the xml nodes
Employee e = new Employee(name,id,age,type);
return e;
}
/**
* I take a xml element and the tag name, look for the tag and get
* the text content
* i.e for <employee><name>John</name></employee> xml snippet if
* the Element points to employee node and tagName is name I will return John
* @param ele
* @param tagName
* @return
*/
private String getTextValue(Element ele, String tagName) {
String textVal = null;
NodeList nl = ele.getElementsByTagName(tagName);
if(nl != null && nl.getLength() > 0) {
Element el = (Element)nl.item(0);
textVal = el.getFirstChild().getNodeValue();
}
return textVal;
}
/**
* Calls getTextValue and returns a int value
* @param ele
* @param tagName
* @return
*/
private int getIntValue(Element ele, String tagName) {
//in production application you would catch the exception
return Integer.parseInt(getTextValue(ele,tagName));
}
/**
* Iterate through the list and print the
* content to console
*/
private void printData(){
System.out.println("No of Employees '" + myEmpls.size() + "'.");
Iterator<Employee> it = myEmpls.iterator();
while(it.hasNext()) {
System.out.println(it.next().toString());
}
}
private void sortByAge(){
Collections.sort(myEmpls);
}
public void run() {
if (out != null){
parseXmlFile();
parseDocument();
writeToStream();
}
if (in != null){
readStream();
sortByAge();
printData();
}
// since i'm using the same class for both the producer and consumer thread
// here, the code above functions as kind of a switch between these 2
// modes of operation, by checking which pipe is initialized.
}
public void writeToStream(){
try{
out.writeObject(myEmpls);
out.flush();
out.close();
pout.flush();
pout.close();
}catch (Exception e) {
System.out.println("ErrorWS:" + e);
}
}
public void readStream(){
try{
myEmpls = (List<Employee>) in.readObject();
in.close();
pin.close();
}catch (Exception e) {
System.out.println("ErrorRS:" + e);
}
}
}
这里的亚军代码:
package domAPI;
import java.io.*;
public class Launcher {
public static void main(String[] args){
Thread t1,t2;
try{
PipedOutputStream pos1 = new PipedOutputStream();
PipedInputStream pis2 = new PipedInputStream(pos1);
t1 = new Thread(new ParserRunnable(pos1,1));
t2 = new Thread(new ParserRunnable(pis2,1));
t1.start();
t2.start();
}catch (Exception e) {
System.out.println("Error:" + e);
}
}
}
我的代码可能会非常棘手的理解。随意轰炸我的问题,我会提供。此外,大多数的XML解析代码源于此:http://totheriver.com/learn/xml/xmltutorial.html#2
我就离开这里XML,以及,如果需要的话:
<?xml version="1.0" encoding="UTF-8"?>
<Personnel>
<Employee type="permanent">
<Name>Seagull</Name>
<Id>3674</Id>
<Age>34</Age>
</Employee>
<Employee type="contract">
<Name>Robin</Name>
<Id>3675</Id>
<Age>25</Age>
</Employee>
<Employee type="permanent">
<Name>Crow</Name>
<Id>3676</Id>
<Age>28</Age>
</Employee>
</Personnel>
的例外,我得到:
ErrorRS:java.io.IOException: Write end dead
No of Employees '0'.
ErrorWS:java.io.IOException: Read end dead
我以前没有在PipedOutput/InputStream上工作过,但是从您的经验来看,我认为关闭PipedOutputStream可能会导致PipedInputStream无法读取数据。在引脚读完所有数据之前,您是否尝试不调用pout.close()?也许作为一个开始,尽量不要调用pout.close()并查看它的行为。 – anonymous
相同的结果... –
为什么这两个线程?为什么不让第二个线程直接读取XML?好处在哪里?不要在不需要它们的地方添加线程。重新考虑你的例外情况,你是否意识到流的终结?关闭管道? – EJP