2017-02-12 15 views
0

Я пытаюсь создать программу, которая пытается расшифровать файл, который был зашифрован с использованием шифрования AES для школьного проекта. У меня есть список ~ 100 000 английских слов и вы хотите реализовать многопоточность внутри программы, чтобы оптимизировать время, затраченное на попытку дешифрования с каждым словом в файле.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(); 
    } 
} 

и осуществления работоспособного классе «взяточника» выглядит следующим образом:

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 
} 

} 

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

Я ищу помощь по позиционированию исполнителя.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

Основная проблема заключается в том, что вы не отправляете свои исполняемые файлы исполнителям. Таким образом, выключение выключения для исполнителя не влияет на все потоки, которые вы породили.

Вместо того, чтобы создать новую тему, а не делать что-то вроде:

executor.submit(grafter) 

Это вы должны получить большую часть пути, но если вы хотите, чтобы служба закрыть быстро и чисто там немного больше вы можете сделать , Ссылка, содержащаяся в комментариях shmosel, должна помочь вам в этом.

Как в стороне, то, как вы это делаете, не будет очень эффективным, я не думаю. По сути, вы создаете новую задачу для каждого слова в словаре, что означает, что у вас есть большое количество задач (100K в вашем случае). Это означает, что накладные расходы на управление и планирование всей этой задачи, вероятно, будут значительной частью работы, выполняемой вашей программой. Вместо этого вы можете разбить список слов на некоторое количество подписчиков, каждый из которых содержит равное количество слов, а затем сделает ваш исполняемый процесс только подвыраженным.

+0

Ха, даже не заметил этого. Хорошее место! –

+0

Ваш последний абзац не совсем прав, поскольку OP использует «FixedThreadPool» - это означает, что должно быть правильное количество потоков.Вы правы, что это не идеальное решение для спама очереди с множеством задач, но не должно быть обмолота, поскольку нет перекомпоновки потоков. –

+0

Несомненно, ситуация была бы хуже, если бы он использовал неограниченный пул потоков, но факт остается фактом: им придется ставить в очередь большое количество задач, а затем пул потоков должен будет деактивировать и разложить все эти задачи перед исполнителями. Я думаю, важно ли это, зависит от того, сколько работы сделана в tryToDecrypt, но я был бы очень удивлен, если бы задача на слово была наиболее эффективным способом сделать это, – d80tb7