Я новичок в Java и, как домашнее задание, я должен реализовать параллелизм к генетическому алгоритму для решения задачи коммивояжера здесь . Наша цель - сделать оценку хромосомы по потокам. Так что я думаю, мне нужно переписать эту часть кода, чтобы быть многопоточным:
// Gets the best tour in the population
public Tour getFittest() {
Tour fittest = tours[0];
// Loop through individuals to find fittest
for (int i = 1; i < populationSize(); i++) {
if (fittest.getFitness() <= getTour(i).getFitness()) {
fittest = getTour(i);
}
}
return fittest;
}
// Gets population size
public int populationSize() {
return tours.length;
}
Изначально я собирался вручную разбить потоки между массивами, но я верю, что это не лучшее решение проблемы. Поэтому я провел небольшое исследование, и все предлагают использовать либо параллельные потоки, либо ExecutorService. Однако у меня были проблемы с применением обоих этих решений, хотя я и пытался подражать примерам, размещенным в других темах. Итак, мои вопросы: как именно я реализую их в этом случае, и какой из них быстрее?
Редактировать: Извините, я забыл опубликовать решение, которое я пробовал. Вот оно:
public Tour getFittest() {
Tour fittest = tours[0];
synchronized (fittest) {
final ExecutorService executor = Executors.newFixedThreadPool(4);
final List<Future<?>> futures = new ArrayList<>();
for (int i = 1; i < populationSize(); i++) {
Future<?> future = executor.submit((Runnable) () -> {
if (fittest.getFitness() <= getTour(i).getFitness()) {
fittest = getTour(i);
}
});
futures.add(future);
}
try {
for (Future<?> future : futures) {
future.get();
}
}catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
return fittest;
}
public int populationSize() {
return tours.length;
}
Однако, при попытке запустить его, я получаю сообщение об ошибке «Локальная переменная, определенная в включенной области видимости, должна быть окончательной или фактически конечной» в строке:
fittest = getTour(i);
И я понятия не имею, почему это происходит или как я могу это исправить, добавив ключевое слово final, а при его инициализации это не исправляется. Кроме этого у меня есть некоторые сомнения по поводу использования синхронизированного ключевого слова в этом решении. Я считаю, что для достижения истинной многопоточности мне нужно использовать его из-за того, что ресурс используется несколькими потоками. Я прав? К сожалению, я не сохранил мою попытку использовать потоки, но мне сложно понять, как это работает вообще.
Edit2: мне удалось «исправить» мое решение, добавив два обходных пути. В настоящее время мой код выглядит так:
public Tour getFittest() {
Tour fittest = tours[0];
synchronized (fittest) {
final ExecutorService executor = Executors.newFixedThreadPool(4);
final List<Future<?>> futures = new ArrayList<>();
for (int i = 1; i < populationSize(); i++) {
final Integer innerI = new Integer(i);
Future<?> future = executor.submit((Runnable) () -> {
if (fittest.getFitness() <= getTour(innerI).getFitness()) {
setFitness(innerI, fittest);
}
}
);
futures.add(future);
}
try {
for (Future<?> future : futures) {
future.get();
}
}catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
return fittest;
}
public int populationSize() {
return tours.length;
}
public Tour setFitness (int i, Tour fittest) {
fittest = getTour(i);
return fittest;
}
Тем не менее, пока он компилируется, есть две проблемы. Использование памяти растет с каждой секундой, в течение которой запускается программа, увеличивая до 16 ГБ ОЗУ за десять секунд, в то время как переменная fittest не изменяется вообще. Так что, думаю, я все еще делаю что-то не так.