Это основано на моем предыдущем вопросе: Подождите в цикле, пока задачи ThreadPoolExecutor не будут выполнены, прежде чем продолжить
Я пытаюсь сделать алгоритм Дейкстры параллельным.Я реализовал CountDownLatch, чтобы дождаться завершения всех задач.Каждая задача смотрит на определенный набор ребер, связанных с текущим узлом в итерации.Таким образом, 8 ребер и 2 потока означают, что каждая задача будет смотреть на 4 ребра.После того, как все задачи будут выполнены, мы перейдем к следующему узлу.
По какой-то причине начальная и конечная точка индекса (количество соединенных ребер) иногда оказывается выше, чем доступные ребра.У меня была эта проблема до CountDownLatch, и я решил, что это из-за задач, не ожидающих завершения, прежде чем мы продолжим.
Чтобы посмотреть на некоторые строки отладки, я добавил Thread.Sleep (100), чтобы посмотреть на вывод, и заметил, что массив не выходит за пределы, когда я замедляю работу.
Наконец, я заметил, что цикл застревает на узле 0, источнике.Это не должно быть возможным, потому что мы начинаем с этого узла и устанавливаем значение true.Я не знаю, если это из-за других ошибок или других ошибок в моем коде.
Эта функция вызывается один раз и будет проходить через все узлы на графике:
public void apply(int numberOfThreads) {
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(numberOfThreads + 1);
CountDownLatch cdl = new CountDownLatch(numberOfThreads);
class DijkstraTask implements Runnable {
private int start;
private int end;
private final CountDownLatch cdl;
public DijkstraTask(int start, int end, CountDownLatch cdl) {
this.start = start;
this.end = end;
this.cdl = cdl;
}
@Override
public void run() {
calculateShortestDistances(start, end, cdl);
}
}
currentNode = 0;
this.nodes[0].setDistanceFromSource(0);
// Visit every node, in order of stored distance
for (int i = 0; i < this.nodes.length; i++) {
// Loop round the edges that are joined to the current node
currentNodeEdges = this.nodes[currentNode].getEdges();
int edgesPerThread = currentNodeEdges.size() / numberOfThreads;
int modulo = currentNodeEdges.size() % numberOfThreads;
System.out.println(i);
//Add task for each node
for (int t = 0; t < numberOfThreads; t++) {
int start = edgesPerThread * t;
int end = edgesPerThread * (t + 1);
executor.execute(new DijkstraTask(start, end, cdl));
System.out.println("Start: " + start + ". End: " + end + ". Total: " + currentNodeEdges.size());
//If we have a modulo we will add another task to look at the remaining edges
if (modulo > 0 && numberOfThreads == (t + 1)) {
start = edgesPerThread * (t + 1);
end = edgesPerThread * (t + 1) + modulo;
executor.execute(new DijkstraTask(start, end, cdl));
System.out.println("Modulo start: " + start + ". End: " + end + ". Total: " + currentNodeEdges.size());
}
}
//wait for all threads to finish
try {
cdl.await();
System.out.println("-all done-");
} catch (InterruptedException ex) {
ex.printStackTrace();
}
// All neighbours are checked so this node is now visited
nodes[currentNode].setVisited(true);
//Look through the results of the tasks and get the next node that is closest by
currentNode = getNodeShortestDistanced();
}
executor.shutdown();
}
Следующая задача вызывается задачей, она обрабатывает подключенные eges от начального индекса до конечного индекса:
public void calculateShortestDistances(int start, int end, CountDownLatch cdl) {
//Process the edges
for (int joinedEdge = start; joinedEdge < end; joinedEdge++) {
// Array goes out of bounds here!
int neighbourIndex = currentNodeEdges.get(joinedEdge).getNeighbourIndex(currentNode);
// Only interested in an unvisited neighbour
if (!this.nodes[neighbourIndex].isVisited()) {
// Calculate the tentative distance for the neighbour
int tentative = this.nodes[currentNode].getDistanceFromSource() + currentNodeEdges.get(joinedEdge).getLength();
// Overwrite if the tentative distance is less than what's currently stored
if (tentative < nodes[neighbourIndex].getDistanceFromSource()) {
nodes[neighbourIndex].setDistanceFromSource(tentative);
}
}
}
cdl.countDown();
}
Спасибо за помощь!
Редактировать: я добавилтрассировка стека:
Exception in thread "pool-1-thread-388" java.lang.IndexOutOfBoundsException: Index: 9, Size: 9
at java.util.ArrayList.rangeCheck(ArrayList.java:657)
at java.util.ArrayList.get(ArrayList.java:433)
at ThreadPool.CalculatePerVertice.calculateShortestDistances(CalculatePerVertice.java:136)
at ThreadPool.CalculatePerVertice$1DijkstraTask.run(CalculatePerVertice.java:76)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
````