2012-02-09 47 views
2

我有一個Java應用程序,我開始100線程。線程在解析xml文件並從中提取一些文本後,打開一個文件來寫入提取的文本。但是,他們似乎混合了結果(輸出文件不是按照假定的順序)。 我用Lock但它沒有解決問題。誰能幫忙?Java多線程混合文本不工作輸出文件鎖

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()); 
    } 
} 




} 
+0

你期望什麼順序? – pingw33n 2012-02-09 10:07:56

回答

3

線:

Lock l=new ReentrantLock(); 

SimpleThread.run()將爲的SimpleThread每個實例的新鎖,其是沒有意義的,所有線程之間的唯一的同步將是FileWrite()方法。如果你想擁有由SimpleThread所有實例共享鎖,然後添加一個static Lock成員變量:

static Lock l = new ReentrantLock(); 

但是,這樣做將意味着線程將順序執行,這使得它非常無意義的有螺紋的。

SimpleThread的另一種方法是解析其XML文件(不需要鎖定)並將結果緩存在內存中(在將存儲要寫入文件的行的ArrayList<String>()中)。 main()線程將等待所有SimpleThread實例完成,然後將每個結果寫入文件。這將允許解析XML併發並確保有序的輸出文件。

+0

+1。我贊同你。我還要說,不使用字符串「ucid」作爲FileWrite類的同步構造函數的參數,並且不建議使用不推薦使用的stop()Thread方法,因爲最好調用t.interrupt()。 – 2012-02-09 11:56:25

0

,你可以嘗試「同步」,這至少在一段時間你的線程中的一個正在運行的保證。

0

如果使用的是100個線程,那麼我建議

  1. 使用線程池 - 東西可以得到與他們

  2. 100個線程,以便更容易爲主題的很多,你爲什麼選擇這麼多?這不是說有更多的線程意味着更快地完成工作(至少並不總是)。 CPU將不得不做很多工作才能正確使用它們,我不認爲你在多核架構上使用這個應用程序。 (> 4爲例)嘗試擴展您的應用程序,並運行一些測試,看看如果從5-10線程得到任何改善,100

編輯您沒有運行的所有100個線程一次,我仍然認爲創建潛在的100個併發線程並不是一個好的選擇。

  1. 不要延長線,但創造了Runnable

  2. 的實施過程中,他們將混合的結果,沒關係,你啓動線程一前一後的順序,他們運行總是不可預測的。

  3. 爲了使它們正確地工作,您可以在SAME鎖上同步它們,但是如果它們將一個接一個地執行,那麼有100個線程的目的是什麼?第二個線程將等待第一個,第三個等待第二個等等...在這種情況下,您可以擺脫線程,並只用一個來完成。 或者你可以實現Callable而不是Runnable,並且傳遞給每個Thread的currect行號,當Thread完成時,它將返回結果與它正在處理的行號。將結果放在PriorityBlockingQueue中,並根據行號對它們進行排序(使用比較器),然後獲取它們並輸出結果。

有些人在這裏誰(我希望)會建議可能更(我真的希望更好)的解決方案也;)

乾杯,尤金。