Построение успешно не отображается после добавления еще одного потока, конвейера взлома пароля

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

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

  2. Почему, когда я добавляю 4-й поток для шифрования, не происходит успешной сборки в конце программы, когда потоки заканчиваются.

Большое спасибо за любой ответ, если нужно что-то, например, мои эксперименты просто спросите.

КОД: Класс шифрования

package passwordcracking;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Encrypt implements Runnable {

private static final Logger LOGGER = Logger.getLogger("passwordCracker");
private final Buffers<String> bufferTakeFrom;
private final Buffers<PairEncPWandClearPW> bufferPutTo;
String possiblePassword;
private MessageDigest messageDigest;

/**
 *
 * @param bufferTakeFrom
 */
public Encrypt(Buffers<String> bufferTakeFrom, Buffers<PairEncPWandClearPW>        

bufferPutTo) 
{
    this.bufferTakeFrom = bufferTakeFrom;
    this.bufferPutTo = bufferPutTo;
    try {
        messageDigest = MessageDigest.getInstance("SHA");
    } catch (NoSuchAlgorithmException ex) {
        LOGGER.log(Level.SEVERE, ex.getMessage());
        throw new RuntimeException(ex);
    }
}

@Override
public void run() {
    do {
        possiblePassword = bufferTakeFrom.take();
        EncryptSingleWord(possiblePassword);
    } while (!possiblePassword.equals("-1"));

}

private void EncryptSingleWord(final String possiblePassword) {
    byte[] digest = null;
    try {
        digest = messageDigest.digest(possiblePassword.getBytes());
        PairEncPWandClearPW pair = new PairEncPWandClearPW(digest, possiblePassword);
        bufferPutTo.put(pair);
    } catch (Exception ex) {
        System.out.println("Exception: " + ex);
        System.out.println("possible password bytes: " + possiblePassword.getBytes());
        System.out.println("password:" + possiblePassword);

    }

}}

Создание вариаций класса:

package passwordcracking;

import utilities.StringUtilities;

/**
 *
 * @author zatokar
 */
public class MakeVariations implements Runnable {

Buffers<String> bufferTakeFrom;
Buffers<String> bufferPutTo;
String dictionaryEntry;

public MakeVariations(Buffers<String> bufferTakeFrom, Buffers<String> bufferPutTo) {
    this.bufferTakeFrom = bufferTakeFrom;
    this.bufferPutTo = bufferPutTo;
}

@Override
public void run() {
    do {
        dictionaryEntry = bufferTakeFrom.take();
        makeVariations(dictionaryEntry);
        if (dictionaryEntry.equals("-1")) {
            System.out.println("Make variations thread finished.");
        }
    } while (!dictionaryEntry.equals("-1"));
}

public void makeVariations(final String dictionaryEntry) {
    final String possiblePassword = dictionaryEntry;
    bufferPutTo.put(dictionaryEntry);
    final String possiblePasswordUpperCase = dictionaryEntry.toUpperCase();
    bufferPutTo.put(possiblePasswordUpperCase);
    final String possiblePasswordCapitalized = StringUtilities.capitalize(dictionaryEntry);
    bufferPutTo.put(possiblePasswordCapitalized);
    final String possiblePasswordReverse = new StringBuilder(dictionaryEntry).reverse().toString();
    bufferPutTo.put(possiblePasswordReverse);
    for (int i = 0; i < 100; i++) {
        final String possiblePasswordEndDigit = dictionaryEntry + i;
        bufferPutTo.put(possiblePasswordEndDigit);
    }
    for (int i = 0; i < 100; i++) {
        final String possiblePasswordStartDigit = i + dictionaryEntry;
        bufferPutTo.put(possiblePasswordStartDigit);
    }
    for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 100; j++) {
            final String possiblePasswordStartEndDigit = i + dictionaryEntry + j;
            bufferPutTo.put(possiblePasswordStartEndDigit);
        }
    }
}
}

Буферный класс:

package passwordcracking;

import java.util.LinkedList;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author zatokar
 */
public class Buffers <T>{
final Queue<T> ll = new LinkedList<>();
int capacity=500000;
public synchronized T take(){

    while (ll.isEmpty()) {
        try {
//             System.out.println("empty");
            wait();
        } catch (InterruptedException ex) {
            Logger.getLogger(Buffers.class.getName()).log(Level.SEVERE, null, ex);
        }
        }
  T element = ll.remove();
  notifyAll();
  return element;

}

    public synchronized void put(T element) {
    while (isFull()) {
        try {

//            System.out.println("full "+element);
            wait();
        } catch (InterruptedException e) {
        }
    }

    ll.add(element);
    notifyAll();
}
  public boolean isFull(){
      return (ll.size()==capacity);
      }


    public boolean isEmpty(){
        if (ll.isEmpty()){
            return true;
        }
        else{
            return false;}
    }
}

Сравнение классов:

пакетный взлом паролей;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Compare implements Runnable {

Buffers<PairEncPWandClearPW> bufferTakeFrom;
final List<UserInfo> userInfos;
byte[] digest;
PairEncPWandClearPW pair;
String possiblePassword;

public Compare(Buffers<PairEncPWandClearPW> bufferTakeFrom) throws IOException {
    this.bufferTakeFrom = bufferTakeFrom;
    userInfos = PasswordFileHandler.readPasswordFile("passwords.txt");
}

@Override
public void run() {
    do {
        pair=bufferTakeFrom.take();
        possiblePassword = pair.getClearPW();
        digest = pair.getEncryptedPW();
        List<UserInfoClearText> list = checkSingleWord(userInfos, digest, 

possiblePassword);
        if (!list.isEmpty()) {
            System.out.println(list);
        }
        if (possiblePassword.equals("-1")) {
            System.out.println("Comparing thread finished.");
            final long endTime = System.currentTimeMillis();
            final long usedTime = endTime - PasswordCracking.startTime;
            System.out.println("Used time: " + usedTime / 1000 + " seconds = " +     

usedTime / 60000.0 + " minutes");
        }
    } while (!possiblePassword.equals("-1"));
}

private List<UserInfoClearText> checkSingleWord(final List<UserInfo> userInfos, final     

byte[] digest, final String possiblePassword) {
    final List<UserInfoClearText> results = new ArrayList<UserInfoClearText>();
    for (UserInfo userInfo : userInfos) {
        if (Arrays.equals(userInfo.getEntryptedPassword(), digest)) {
           results.add(new UserInfoClearText(userInfo.getUsername(),     

possiblePassword));
        }
    }
    return results;
}
}

2 ответа

Решение

Попробуйте использовать SynchronousQueue вместо вашего собственного класса Buffers. Я уверен, что это также значительно улучшит скорость (из-за вашей синхронизированной реализации).

Кроме этого, ваша архитектура сомнительна. Это требует SynchroneousQueue, чтобы не допустить переполнения / недополнения потоков обработки генерирующими потоками, почему эти потоки обработки не генерируют свою собственную работу?

Вы можете написать Runnable, который принимает одно слово из словаря, генерирует варианты и затем проверяет их на соответствие реальному паролю. Это не только сильно упростит код, но и обеспечит 100% -ную работу потоков над реальной проблемой, и вам не придется беспокоиться о том, сколько потоков потратить на что.

Окей, благодаря TwoThe он почти полностью решил мою проблему. Основное ускорение состояло в замене очереди LinkedList на LinkedBlockingQueue (он ответил мне, что я должен использовать SynchronousQueue, но в нем не реализован конструктор емкости), который используется с конструктором емкости, что необходимо, потому что после внесения изменений и помещения его в LinkedList вы наверняка получить OutOfMemoryException. Спасибо большое, скорость в 3 раза меньше. Проблема была в моей собственной синхронизации в буферном классе.

Другие вопросы по тегам