我正在處理這個程序,它應該使用第一個線程反序列化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