синхронизировать состояния между несколькими потоками - PullRequest
1 голос
/ 19 июня 2019

У меня есть таблица и несколько ботов (пока только 2), которые пытаются найти кратчайший путь в таблице от начальной точки до цели.

Каждый бот - это поток, который сохраняет состояниезаблокированных и неблокированных клеток в таблице.

Каждый поток подписан на другие темы.Когда один поток выполняет и перемещается, он отправляет уведомление другим потокам о том, что он освободил ранее занятую ячейку и заблокировал другую.

Это выглядит так

enter image description here

Основной цикл каждого потока выглядит следующим образом

@Override
public void run() {
    // render original position
    notifyObserver(ChangeStateEvent
        .builder()
        .identifier(npc.getIdentifier())
        .newState(
            NPCWalkState.builder()
                .row(startVertex.getRow())
                .column(startVertex.getColumn())
                .build())
        .build());
    while (!startVertex.equals(goalVertex)) {
        ThreadUtils.delaySeconds(speed);

        Vertex nextStep = pathSearch.find(startVertex, goalVertex, cellStates).get(1);

        ChangeStateEvent event = ChangeStateEvent.builder()
            .identifier(npc.getIdentifier())
            .newState(
                NPCWalkState.builder()
                    .row(nextStep.getRow())
                    .column(nextStep.getColumn())
                    .build())
            .previousState(
                NPCWalkState.builder()
                    .row(startVertex.getRow())
                    .column(startVertex.getColumn())
                    .build())
            .build();
        notifyObserver(event);
        startVertex = new Vertex(nextStep);
    }
}

И метод слушателя выглядит следующим образом

@Override
public void receiveNotification(ChangeStateEvent data) {
    if (null != data.getPreviousState()) {
        // freed cells
        int free_row = data.getPreviousState().getRow();
        int free_column = data.getPreviousState().getColumn();
        // blocked cells
        int blocked_row = data.getNewState().getRow();
        int blocked_column = data.getNewState().getColumn();

        cellStates[free_row][free_column] = false;
        cellStates[blocked_row][blocked_column] = true;
    } else {
        // blocked cells
        int blocked_row = data.getNewState().getRow();
        int blocked_column = data.getNewState().getColumn();

        cellStates[blocked_row][blocked_column] = true;
    }
}

cellStates - это базовая логическая матрица

private boolean[][] cellStates;

Но иногда эти движущиеся боты перекрывают друг друга - поэтому они одновременно попадают в одни и те же ячейки.В конце концов они достигают желаемого пункта назначения.

Однако я бы хотел избавиться от этого поведения.Как этого добиться?

Насколько я понимаю, я должен запретить поиск, пока в сообщении receiveNotification не будет обновлено состояние cellState, или запретить обновление cellState, если поиск начался.

Я также не исключаю, что сама таблица отвечает за это перекрытие - поскольку она также подписана на события потоков

@Override
public void receiveNotification(ChangeStateEvent data) {
    if (null != data.getPreviousState()) {
        int previousRow = data.getPreviousState().getRow();
        int previousColumn = data.getPreviousState().getColumn();
        int currentRow = data.getNewState().getRow();
        int currentColumn = data.getNewState().getColumn();
        SwingUtilities.invokeLater(() -> {
            List<T> oldCellContent = (List<T>) table.getValueAt(previousRow, previousColumn);
            oldCellContent.remove(data.getIdentifier());
            table.setValueAt(oldCellContent, previousRow, previousColumn);

            List<T> newCellContent = (List<T>) table.getValueAt(currentRow, currentColumn);
            newCellContent.add(0, (T) data.getIdentifier()); // on top TODO: player should be prioritized
            table.setValueAt(newCellContent, currentRow, currentColumn);
        });
    } else {
        int currentRow = data.getNewState().getRow();
        int currentColumn = data.getNewState().getColumn();
        SwingUtilities.invokeLater(() -> {
            List<T> newCellContent = (List<T>) table.getValueAt(currentRow, currentColumn);
            newCellContent.add(0, (T) data.getIdentifier());
            table.setValueAt(newCellContent, currentRow, currentColumn);
        });
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...