我有一个 Java 应用程序,在其中启动了 100 个线程。线程在解析 xml 文件并从中提取一些文本后,打开一个文件以写入提取的文本。然而,它们似乎混合了结果(输出文件不符合预期的顺序)。 我使用了Lock,但没有解决问题。有人可以帮忙吗?
Main.java
public class Main {
public static void main(String[] args) throws FileNotFoundException, IOException, InterruptedException {
FileInputStream fstream = new FileInputStream("C:\\Users\\Michael\\outfilenames0.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
String strLine;
int j=0;
while (((strLine = br.readLine()) != null) && (j<100))
{
int activethreads=Thread.activeCount();
SimpleThread t=new SimpleThread(strLine);
t.start();
if (activethreads>100)
SimpleThread.sleep(250);
if (j==99)
{j=-1;}
//System.out.println(t.getName());
j++;
}
}
}
class SimpleThread extends Thread {
private String str;
public SimpleThread(String str) {
this.str=str;
}
@Override
public void run() {
try {
Lock l=new ReentrantLock();
if (l.tryLock()){
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
// create SAX-parser...
SAXParser parser=factory.newSAXParser();
SaxHandler handler = new SaxHandler();
parser.parse(str, handler);
} catch (ParserConfigurationException ex) {
Logger.getLogger(SimpleThread.class.getName()).log(Level.SEVERE, null, ex);
}finally {l.unlock();}
} else Thread.currentThread().sleep(10);
} catch (InterruptedException ex) {
Logger.getLogger(SimpleThread.class.getName()).log(Level.SEVERE, null, ex);
} catch (SAXException ex) {
Logger.getLogger(SimpleThread.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(SimpleThread.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
class SaxHandler extends DefaultHandler {
private boolean invention_title = false;
private boolean invention_title_lang = false;
private boolean abstr = false;
private boolean abstr_lang = false;
private boolean descr = false;
private boolean description_lang = false;
private String doc="";
private String ucid;
@Override
public void startElement(String uri, String localName,
String qName, Attributes attrs) throws SAXException {
if (qName.equals("patent-document")) {
ucid = attrs.getValue("ucid");
doc= ("<DOC>\n<DOCNO> " + ucid +"</DOCNO> \n<TEXT>" );
}
if (qName.equalsIgnoreCase("invention-title")) {
invention_title = true;
String title_language = attrs.getValue("lang");
if (title_language.equals("EN"))
{
invention_title_lang = true;
doc=doc+"<TITLE>"+"\n";
}
}
if (qName.equalsIgnoreCase("abstract")) {
abstr = true;
String abst_language = attrs.getValue("lang");
if (abst_language.equals("EN")) {abstr_lang = true;
doc=doc+"<ABSTRACT>"+"\n" ;
}
}
if (qName.equalsIgnoreCase("description")) {
descr = true;
String des_language = attrs.getValue("lang");
if (des_language.equals("EN")) {description_lang = true;
doc=doc+"<DESCRIPTION>"+"\n";
}
}}
@Override
public void endElement (String uri, String localName, String qName)
throws SAXException
{
if((qName.equals("abstract"))&& (abstr_lang)){
abstr_lang = false;
doc=doc+"</ABSTRACT>"+"\n";
}
if((qName.equals("invention-title"))&&(invention_title_lang)){
invention_title_lang = false;
doc=doc+"</TITLE>"+"\n";
}
if((qName.equals("description"))&&(description_lang)){
description_lang = false;
doc=doc+"</DESCRIPTION>"+"\n";
}
if(qName.equals("patent-document")){
doc=doc+"</TEXT>"+"\n"+"</DOC>"+"\n";
//System.out.println("</DOC>");
//Lock l=new ReentrantLock();
// if (l.tryLock())
//try {
FileWrite fileWrite = new FileWrite();
try {
fileWrite.FileWrite(ucid, doc);
} catch (IOException ex) {
Logger.getLogger(SaxHandler.class.getName()).log(Level.SEVERE, null, ex);
}
// }finally {l.unlock();}
// catch (IOException ex) {
//Logger.getLogger(SaxHandler.class.getName()).log(Level.SEVERE, null, ex);
// }
}
}
@Override
public void characters(char ch[], int start, int length)
throws SAXException {
if ( invention_title_lang) {
doc=doc+ (new String(ch, start, length))+"\n";
}
if ( abstr_lang) {
doc=doc+ (new String(ch, start, length));
}
if ( description_lang) {
doc=doc+ (new String(ch, start, length));
}
}
}
class FileWrite
{
public synchronized void FileWrite(String ucid, String doc) throws IOException
{
Thread t=Thread.currentThread();
try{
FileWriter fstreamout = new FileWriter("EP-022",true);
BufferedWriter out = new BufferedWriter(fstreamout);
out.write(doc);
out.close();
if (t.isAlive())
{
t.stop();}
}
catch (Exception e)
{
System.err.println("Error"+e.getMessage());
}
}
}
最佳答案
行:
Lock l=new ReentrantLock();
在 SimpleThread.run()
将为 SimpleThread
的每个实例创建一个新锁这是毫无意义的,所有线程之间唯一的同步将是 FileWrite()
方法。如果您想让 SimpleThread
的所有实例共享一个锁然后添加 static Lock
成员变量:
static Lock l = new ReentrantLock();
但是,这样做意味着线程将按顺序执行,这使得拥有线程毫无意义。
替代方案是 SimpleThread
解析其 XML 文件(不需要锁)并将结果缓存在内存中(在 ArrayList<String>()
中,它将存储要写入文件的行)。 main()
线程将等待所有 SimpleThread
实例完成,然后将每个结果写入文件。这将允许 XML 的解析是并发的并确保输出文件有序。
关于Java多线程在不工作的输出文件锁定中混合文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9208726/