2012-02-09 3 views
2

У меня есть приложение Java, в котором я запускаю 100 потоков. Потоки, после разбора XML-файлов и извлечения из них какого-либо текста, откройте файл для записи извлеченного текста. Однако кажется, что они смешивают результаты (выходной файл не находится в предполагаемом порядке). Я использовал Lock, но это не решило проблему. Может ли кто-нибудь помочь?Java многопоточность смешивает текст в нерабочем режиме file-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()); 
    } 
} 




} 
+0

Какой заказ вы ожидаете? – pingw33n

ответ

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, не используется, а использование метода устаревших стоп() не рекомендуется, потому что лучше вызвать t.interrupt(). –

0

Вы можете попробовать синхронизировать, это по крайней мере гарантирует, что один из ваших потоков запущен.

0

Если вы используете 100 Темы, то я хотел бы предложить

  1. использовать пул темы - вещи могут получить намного проще с ними

  2. 100 Threads много нитей, почему вы выбрали так много? Это не похоже на то, что больше потоков означает выполнение работы быстрее (не всегда). ЦП должен будет много работать, чтобы правильно играть с ними, и я не думаю, что вы используете это приложение в многоядерной архитектуре. (> 4, например) Попробуйте масштабировать приложение и запустить несколько тестов, чтобы увидеть, если вы получаете какие-либо улучшения от 5-10 до 100. Тем

EDIT Вы не работают на все 100 Темы в то время я все еще думаю, что создание потенциально 100 одновременных потоков не является хорошим вариантом.

  1. Не расширяйте тему, но создать реализацию для Runnable

  2. Конечно, они будут смешиваться результаты, это не имеет значения, что вы начинаете Темы один за другим, порядок, в котором они run всегда непредсказуем.

  3. Чтобы сделать их правильно выполненными, вы можете синхронизировать их с SAME lock, но тогда для чего существует 100 потоков, если они будут выполняться один за другим?Второй поток будет ждать первого, третий будет ждать второго и т. Д. ... в этом случае вы могли бы избавиться от потоков и сделать это всего одним. ИЛИ вы могли бы реализовать Callable вместо Runnable и передать каждому потоку номер строки, когда Thread будет выполнен, он вернет результат с номером строки, с которым он имел дело. Поместите этот результат в PriorityBlockingQueue и отсортируйте его в соответствии с номером строки (используя Comparator), а затем просто получите их и выведите результат.

Есть здесь люди, которые (я надеюсь) предположит, вероятно, больше (и я действительно надеюсь, что лучше) решения также;)

Приветствия, Юджин.