2017-08-11 7 views
0

私はここで私の問題に対する答えを見つけようとしましたが、その豊富さと多様性のためにいくらか混乱しました。ここで私の質問です:私のアプリは2つのファイルを比較し、Swing.JTextPaneの結果を出力します。私はボタンでファイルを処理するコードを呼び出し、私はSwingWorkerでファイルの各ペアを処理するUIを停止することを避けるために。ここではそのコードは次のとおりです。doInBackground()比較を行いSwingWorkerが終了するのを待ってからもう一度実行してください

class ProcessAndPrintTask extends SwingWorker<Void, Void> { 
     private Report report; 
     Integer reportResult; 
     ProcessAndPrintTask(Report report) { 
      this.report = report; 
      reportResult = null; 
     } 

     @Override 
     protected Void doInBackground() { 

      try { 
       reportResult = report.getComparator().compareTwoFiles(new FileInputStream(new File(pathToReportsA + report.getFilename())), 
         new FileInputStream(new File(pathToReportsB + report.getFilename()))); 
      } 

      catch (IOException ex) { 
       ex.printStackTrace(); 
      } 

      return null; 
     } 

     @Override 
     protected void done() { 

      String message = report.getFilename() + ": "; 
      if (reportResult != null) { 
       switch (reportResult) { 
        case 1: 
         StyleConstants.setBackground(style, Color.GREEN); 
         try { 
          doc.insertString(doc.getLength(), message + "MATCH\n", style); 
         } 
         catch (BadLocationException ex) {ex.printStackTrace();} 
         break; 
        case 0: 
         StyleConstants.setBackground(style, Color.RED); 
         try { 
          doc.insertString(doc.getLength(), message + "NO MATCH\n\n", style); 
          try { 
           for (String s : report.getComparator().getDifferences(
             new FileInputStream(new File(pathToReportsA + report.getFilename())), 
             new FileInputStream(new File(pathToReportsB + report.getFilename())))) { 
            doc.insertString(doc.getLength(), s + "\n", style); 
           } 
          } catch (Exception ex) { 
           ex.printStackTrace(); 
          } 
         } 
         catch (BadLocationException ex) {ex.printStackTrace();} 
         break; 
        case -1: 
         StyleConstants.setBackground(style, Color.CYAN); 
         try { 
          doc.insertString(doc.getLength(), message + "BOTH FILES EMPTY\n", style); 
         } 
         catch (BadLocationException ex) {ex.printStackTrace();} 
         break; 
        default: 
         StyleConstants.setBackground(style, Color.ORANGE); 
         try { 
          doc.insertString(doc.getLength(), message + "PROBLEM\n", style); 
         } 
         catch (BadLocationException ex) {ex.printStackTrace();} 

       } 
      } 
      else { 
       StyleConstants.setBackground(style, Color.ORANGE); 
       try { 
        doc.insertString(doc.getLength(), message + "FILE OR FILES NOT FOUND\n", style); 
       } 
       catch (BadLocationException ex) {ex.printStackTrace();} 
      } 

     } 
    } 

done()は、比較の結果に応じてメッセージをフォーマットし、それを印刷します。問題は、プログラムが1ペアが処理されて印刷されるまで待たずに、結果が開かれた順番に印刷されないようにすることです。これはユーザーにとって非常に混乱する可能性があります。ファイルのほとんどは小さく、したがって、比較はある時点で完了したように見えますが、まだ処理されている大きなファイルがあります。

私はPropertyChangeListenerを使用しての可能性について読んで私はそれがdone()メソッドを使用してからどのように異なるかを見ていない...ことである(私はdoInBackground()の両方を比較して印刷を実行しようとしたが、これは書式設定を台無しに印刷が完了する前に、背景色が変更されます)。醜い松葉杖のようです

try (FileInputStream reportListExcelFile = new FileInputStream(new File(reportListPath))) { 
       Workbook workbook = new XSSFWorkbook(reportListExcelFile); 
       Sheet sheet = workbook.getSheetAt(0); 
       Iterator<Row> iter = sheet.iterator(); 

       // skip first row that contains columns names 
       iter.next(); 

       while (iter.hasNext()) { 
        try {Thread.sleep(1000);} catch (Exception ex) {ex.printStackTrace();} 
        Row r = iter.next(); 
        String name = r.getCell(0).getStringCellValue(); 
        String format = r.getCell(1).getStringCellValue(); 
        Report currentReport = new Report(name, format); 
        new ProcessAndPrintTask(currentReport).execute(); 
       } 
      } 

だけでなく、GUIは、すべてのファイルまでハングアップする原因:私はまた、このように見えたSwingWorkerを呼び出すループ内の任意の時間のためにThread.sleep()を起動しようとしましたペアを比較した。

解決策はありますか?

+1

あなたは単に起動する必要があります最初の 'done'メソッドからの2番目の' SwingWorker'また 'SwingWorker'を1つだけ使用して、両方のタスクを1つの' doInBackground'メソッドで開始することができます。 –

+0

しかし、私は 'SwingWorker'に' Report'のコレクションを渡さなければなりませんでした。 – DCzo

+0

それを試して、完璧に働いた - ありがとう! – DCzo

答えて

1

一度私はOrderedResultsExecutorsを実行して、結果を通知する順序でタスクを追加する順序を維持します。あなたのためにnotifyメソッドを実装するだけです。 Listenerなどを書いてください。もちろん、レポートのコレクションをSwingWorkerに渡してforループで処理することもできますが、その場合はマルチスレッド化が失われ、すべてのタスクがこのようなシングルスレッド方式で実行するにはかなりの時間がかかります。 、

Import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.ConcurrentHashMap; 
import java.util.concurrent.ConcurrentLinkedDeque; 
import java.util.concurrent.ExecutionException; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Future; 
import java.util.concurrent.LinkedBlockingQueue; 
import java.util.concurrent.ThreadPoolExecutor; 
import java.util.concurrent.TimeUnit; 
import java.util.concurrent.atomic.AtomicLong; 

public class OrderedResultsExecutors extends ThreadPoolExecutor { 
    public OrderedResultsExecutors(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, 
      BlockingQueue<Runnable> workQueue) { 
     super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); 
    } 

    private ConcurrentHashMap<Long, Runnable> startedTasks = new ConcurrentHashMap<>(); 
    private ConcurrentLinkedDeque<Runnable> finishedTasks = new ConcurrentLinkedDeque<>(); 
    private AtomicLong toNotify = new AtomicLong(0); 
    private AtomicLong submitedCount = new AtomicLong(0); 

    @Override 
    protected void beforeExecute(Thread t, Runnable r) { 
     super.beforeExecute(t, r); 
     startedTasks.put(submitedCount.getAndIncrement(), r); 
    } 

    @Override 
    protected void afterExecute(Runnable r, Throwable t) { 
     super.afterExecute(r, t); 
     finishedTasks.add(r); 
     finishedTask(); 
    } 

    private void finishedTask() { 
     Runnable orderedResult; 
     long current; 
     while ((orderedResult = startedTasks.get(current = toNotify.get())) != null 
       && finishedTasks.contains(orderedResult) && (orderedResult = startedTasks.remove(current)) != null) { 
      finishedTasks.remove(orderedResult); 
      notify(current, orderedResult); 
      toNotify.incrementAndGet(); 
     } 
    } 

    private void notify(long order, Runnable result) { 
     try { 
      System.out.println("order: " + order + " result: " + ((Future)result).get()); 
     } catch (InterruptedException | ExecutionException e) { 
      e.printStackTrace(); 
     } 
    } 

    public static ExecutorService newFixedThreadPool(int noOfThreads) { 
     int corePoolSize = noOfThreads; 
     int maximumPoolSize = noOfThreads; 
     return new OrderedResultsExecutors(corePoolSize, maximumPoolSize, 0L, TimeUnit.MILLISECONDS, 
       new LinkedBlockingQueue<Runnable>()); 
    } 

} 
+0

ありがとうございますが、私はより高いレベルのソリューションを望んでいました。Serqiy Medvynskyyが彼のコメントで示唆したものでした。 – DCzo

+0

あなたが本当にこれらのタスクの並列実行を必要としない場合(それらはすべて非常に短い時間がかかります)、@SergiyMedvynskyyによって提供されるソルーションは本当に良くてシンプルです。 –

+0

それは本当です - パラレル実行は本当に必要ではありませんでした。私のために重要な部分は、GUIの応答性を保つことでした。とにかくありがとうございました :)。 – DCzo

0

(Sergiy Medvynskyyによって提案された)答えはループ内で呼ばれる「無限に多くの」SwingWorkersを取り除くことです。このようなメカニズムのラリーマルチスレッド版を持っている方が良いかもしれない理由は、このように、です処理して印刷するアイテムのリストを使用するものを1つだけ作成し、doInBackground()の内部でループを実行します。

リファクタリング後のコードは次のようになります。

class ProcessAndPrintTask extends SwingWorker<Void, Void> { 
     private List<Report> reports; 
     Integer reportResult; 

     ProcessAndPrintTask(List<Report> reports) { 
      this.reports = reports; 

     } 

     @Override 
     protected Void doInBackground() { 
      for (Report report : reports) { 
       try { 
        reportResult = report.getComparator().compareTwoFiles(new FileInputStream(new File(pathToReportsA + report.getFilename())), 
          new FileInputStream(new File(pathToReportsB + report.getFilename()))); 
       } catch (IOException ex) { 
        ex.printStackTrace(); 
       } 
       String message = report.getFilename() + ": "; 
       if (reportResult != null) { 
        switch (reportResult) { 
         case 1: 
          StyleConstants.setBackground(style, Color.GREEN); 
          try { 
           doc.insertString(doc.getLength(), message + "MATCH\n", style); 
          } catch (BadLocationException ex) { 
           ex.printStackTrace(); 
          } 
          break; 
         case 0: 
          StyleConstants.setBackground(style, Color.RED); 
          try { 
           doc.insertString(doc.getLength(), message + "NO MATCH\n\n", style); 
           try { 
            for (String s : report.getComparator().getDifferences(
              new FileInputStream(new File(pathToReportsA + report.getFilename())), 
              new FileInputStream(new File(pathToReportsB + report.getFilename())))) { 
             doc.insertString(doc.getLength(), s + "\n", style); 
            } 
           } catch (Exception ex) { 
            ex.printStackTrace(); 
           } 
          } catch (BadLocationException ex) { 
           ex.printStackTrace(); 
          } 
          break; 
         case -1: 
          StyleConstants.setBackground(style, Color.CYAN); 
          try { 
           doc.insertString(doc.getLength(), message + "BOTH FILES EMPTY\n", style); 
          } catch (BadLocationException ex) { 
           ex.printStackTrace(); 
          } 
          break; 
         default: 
          StyleConstants.setBackground(style, Color.ORANGE); 
          try { 
           doc.insertString(doc.getLength(), message + "PROBLEM\n", style); 
          } catch (BadLocationException ex) { 
           ex.printStackTrace(); 
          } 

        } 
       } 
       else { 
        StyleConstants.setBackground(style, Color.ORANGE); 
        try { 
         doc.insertString(doc.getLength(), message + "FILE OR FILES NOT FOUND\n", style); 
        } 
        catch (BadLocationException ex) { 
         ex.printStackTrace(); 
        } 
       } 
      } 
      return null; 
     } 
    } 

そして、ここでは私が呼んSwingWorker.execute()

try (FileInputStream reportListExcelFile = new FileInputStream(new File(reportListPath))) { 
       Workbook workbook = new XSSFWorkbook(reportListExcelFile); 
       Sheet sheet = workbook.getSheetAt(0); 
       Iterator<Row> iter = sheet.iterator(); 
       java.util.List<Report> reports = new ArrayList<>(); 
       // skip first row that contains columns names 
       iter.next(); 

       while (iter.hasNext()) { 
        Row r = iter.next(); 
        String name = r.getCell(0).getStringCellValue(); 
        String format = r.getCell(1).getStringCellValue(); 
        Report currentReport = new Report(name, format); 
        reports.add(currentReport); 
       } 
       new ProcessAndPrintTask(reports).execute(); 
      } 

それは非常にきれいではないのですが、それは動作します:)

関連する問題