2017-02-12 7 views
0

学校プロジェクト用にAES暗号化を使用して暗号化されたファイルの復号化を試みるプログラムを作成しようとしています。 〜10万語のリストがあり、プログラム内でマルチスレッドを実装して、ファイル内のすべての単語で解読を試みるのにかかる時間を最適化したい。Java - リクエスト時に並行スレッドをシャットダウンする

復号化が正常に完了したときに検索されている辞書の残りの部分を停止しようとすると問題が発生します - 「シャットダウンを試みています」がコンソールに表示されていますが、エグゼキュータが新しいスレッドの割り当てを停止する前に、辞書の残りの部分。私のメインプログラムで

、スレッドはこの方法で使用して実行されます:

private void startThreads(){ 
    ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); 
    System.out.println("Maximum threads inside pool " + executor.getMaximumPoolSize()); 
    for (int i = 0; i < dict.size(); i++) { 
     String word = dict.get(i); 
     Grafter grafter = new Grafter("Grafter " + i,word); 
     grafter.registerWorkerListener(thread -> { 
      List results = thread.getResults(); 
      for (Iterator iter = results.iterator(); iter.hasNext();) { 
       found = (boolean) iter.next(); 
       if(found){ 
        System.out.println("THE WORD HAS BEEN FOUND!! Attempting shutdown"); 
        executor.shutdown(); 
       } 
      } 
     }); 

     // Start the worker thread 
     Thread thread = new Thread(grafter); 
     thread.start(); 

    } 
    if(!executor.isShutdown()) { 
     executor.shutdown(); 
    } 
} 

をし、次のように「grafter」実行可能なクラスの実装は次のとおりです。

public class Grafter implements Runnable{ 

private String NAME; 
private final String WORD; 
private List listeners = new ArrayList(); 
private List results; 

public Grafter(String name, String word){ 
    NAME = name; 
    WORD = word; 
} 

public String getName(){ 
    return NAME; 
} 

@Override 
public void run() { 
    if (tryToDecrypt(WORD) == true){ 
     System.out.println("Thread: '" + NAME + "' successfully decrypted using word: \"" + WORD + "\"."); 
     results = new ArrayList(); 
     results.add(true); 

     // Work done, notify listeners 
     notifyListeners(); 
    }else{ 
     results = new ArrayList(); 
     results.add(false); 

     // Work done, notify listeners 
     notifyListeners(); 
    } 
} 

private void notifyListeners() { 
    for (Iterator iter = listeners.iterator(); iter.hasNext();) { 
     GrafterListener listener = (GrafterListener) iter.next(); 
     listener.workDone(this); 
    } 
} 

public void registerWorkerListener(GrafterListener listener) { 
    listeners.add(listener); 
} 

public List getResults() { 
    return results; 
} 

private boolean tryToDecrypt(String word){ 
    //Decryption performed, returning true if successfully decrypted, 
    //Returns false if not 
} 

} 

正しい言葉は正しいです辞書の先頭にあるので、プログラムの実行の早い段階で成功が見られます。ただし、プログラムが終了するまでに長い休止時間(辞書の残りの部分が処理されるため)があります。

私はexecutor.shutdown()の位置付けと、復号化が正常に完了した後で解析されている辞書の残りの部分を止める方法を探しています。

+0

私はこれを投稿する前に前の投稿をチェックしましたが、 'executor.shutdownNow();の提案を使用した後も同じ問題が発生していました。 executor.awaitTermination(); 'そのスレッドで – user3379139

+2

中断の処理についての部分を読んでください。 – shmosel

+0

[Shmosel](https://stackoverflow.com/users/1553851/shmosel)はまさに正しいです。 [優雅に割り込みを処理する](https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html)が必要で、 'shutdownNow'を呼び出します。 –

答えて

1

あなたの主な問題は、実行ファイルをエグゼキュータに実際に提出していないことです。したがって、エグゼキュータのshutdownを呼び出すことは、あなたが生成したすべてのスレッドには影響を与えません。

代わりの代わりのような何かをする新しいスレッドを作成:これはあなたの道のほとんどを取得する必要があります

executor.submit(grafter) 

ていますが、サービスは迅速かつ正常にシャットダウンしたい場合はもう少しあなたが行うことができますがあります。 shmoselのコメントに記載されているリンクは、あなたに役立つはずです。

あなたがこれをやっているやり方は、私が考えないと非常に効率的になるわけではありません。基本的には、辞書内のすべての単語に対して新しいタスクを作成しています。つまり、多数のタスク(あなたの場合は100K)があることを意味します。これは、すべてのタスクを管理およびスケジューリングするオーバーヘッドが、プログラムによって実行される作業の重要な部分である可能性が高いことを意味します。その代わりに、単語のリストをいくつかのサブリストに分割し、それぞれが同じ数の単語を含むようにして、実行可能なプロセスをサブリストのみにすることができます。

+0

ハ、それに気付かなかった。良い点! –

+0

あなたの最後の段落はOPが 'FixedThreadPool'を使用しているので正確に正しくありません - これは正しい数のスレッドがあるはずであることを意味します。大量のタスクを含むキューを迷惑メールにするのは理想的ではありませんが、スレッドのオーバーコミットがないので、スラッシングする必要はありません。 –

+0

確かに、無制限のスレッドプールを使用すると状況が悪化する可能性がありますが、実際には多数のタスクをキューに入れなければならず、スレッドプールはデキューしてすべてを取り出す必要がありますエグゼクティブにそれらの仕事。私はそれが重要かどうかは、tryToDecryptでどのくらいの作業が行われたかによって変わりますが、単語ごとのタスクがこれを行う最も効率的な方法であれば、私は非常に驚くでしょう。 – d80tb7

関連する問題