Как я могу прервать последовательность процедур в Java?

StackOverflow https://stackoverflow.com/questions/2034520

Вопрос

У меня есть куча процедур, которые необходимо выполнять последовательно, пока либо все они не будут выполнены, либо не будет выполнено определенное условие.Вот базовый код, который необходимо выполнять до тех пор, пока не будет выполнено условие:

public boolean search()
{
    robot.go();

    robot.spin();

    //etc - around 8 more similar commands (each takes around 2 seconds)
    return false; //didn't find what it was looking for
}

До сих пор единственный способ, которым я думал о том, чтобы сделать то, что я хотел, - это:

public boolean search()
{
    robot.go(false);
    while(robot.isMoving())
    {
        if(thingFound())
        {
            robot.stop()
            return true;
        }
        Thread.yield();
    }

    robot.spin(false);
    while(robot.isMoving())
    {
        if(thingFound())
        {
            robot.stop()
            return true;
        }
        Thread.yield();
    }


    //etc - around 8 more similar commands
    return false; //didn't find what it was looking for
}

В false параметр для go() и spin() указывает, что они должны вернуться немедленно, позволяя проверить условие.Однако такой подход кажется мне довольно неэффективным, поскольку один и тот же блок кода должен повторяться 10 раз.Может ли это быть достигнуто более эффективно с помощью исключений или параллельных потоков?

Это было полезно?

Решение

по мотивам книги Джонатана Леффлера ответ:
вы можете использовать Runnable как указатель к командам

private final Runnable going = new Runnable() {
    @Override
    public void run() {
        robot.go(false);
    }
});

private final Runnable spinning = new Runnable {
    @Override
    public void run() {
        robot.spin(false);
    }
});

// other commands 


private boolean isFoundAfter(Runnable command)
{
    command.run();
    while (robot.isMoving())
    {
        if (thingFound())
        {
            robot.stop()
            return true;
        }
        Thread.yield();
    }
    return false;
}

public boolean search()
{
    if (isFoundAfter(going)) return true;

    if (isFoundAfter(spinning)) return true;   

    //etc - around 8 more similar commands
    return false; //didn't find what it was looking for
}


еще один шаг, если это уместно, поместите команды в массиве или списке и выполните его как скрипт

...

private boolean executeSearch(Runnable... commands)
{
    for (Runnable cmd : commands) {
        if (isFoundAfter(cmd)) return true;
    }
    return false; //didn't find what it was looking for
}

public boolean search() {
    return executeSearch(going, spinning /* around 8 more similar commands */);
}

Другие советы

Не уверен, почему вы используете Thread.yield() - выполняются ли другие потоки, о которых вы не упомянули?Или, может быть, я неправильно истолковал проблему.

Я думаю, возможно, здесь мог бы сработать Командный шаблон.У вас был бы RobotCommand интерфейс с execute способ и реализация RobotCommand в зависимости от типа команды (вперед, вращение и т.д.).Тогда вы могли бы построить RobotAlgorithm в качестве List из RobotCommand, и иметь метод executeRobotAlgorithm который повторил процедуру по списку, вызывая execute на каждом RobotCommand и проверка результата thingFound() после каждого из них.

Редактировать - о, кажется, я понял.Делай go и spin запускать потоки, которые изменяют состояние робота, или что-то в этом роде?

Правка 2 - в ответ на ваш комментарий, похоже, проблема здесь в том, что вам нужно иметь возможность немедленно вернуться, если робот найдет то, что ищет, но go, spin, команды , etc не будут делать этого прямо сейчас, и вам нужна возможность продолжать выполнять новые команды в то же время.Итак, что я мог бы сделать здесь, так это иметь два потока - один был бы потоком "исполнителя", который выполнял бы ваш List из RobotCommands один за другим, и поток "наблюдателя", который будет неоднократно переходить в спящий режим и опрашивать (проверьте thingFound()).Если thingFound() когда-либо это правда, тогда вы можете остановить своего робота, а также поток исполнителя, или если исполнитель доберется до конца раньше thingFound() является истинным, то он может сигнализировать как таковой (при необходимости).

Очевидно, что цикл while может быть упакован в его собственную функцию:

private boolean isFound()
{
    while (robot.isMoving())
    {
        if (thingFound())
        {
            robot.stop()
            return true;
        }
        Thread.yield();
    }
    return false;
}

public boolean search()
{
    robot.go(false);
    if (isFound()) return true;

    robot.spin(false);
    if (isFound()) return true;   

    //etc - around 8 more similar commands
    return false; //didn't find what it was looking for
}

(Я не возражаю, если условие будет разделено на две строки;Я бы, вероятно, сделал это в производственном коде.)

Лучший Java-программист, чем я, может сказать вам, можете ли вы передавать "процедуры" (указатели на функции, в терминах программирования на C). Я подозреваю, что вы можете, но я не знаю синтаксиса и правил. В доказательства похоже, что ты не можешь (во всяком случае, примерно в 2004 году).

робот может использовать объект Condition для подачи сигнала контроллеру о том, что он выполнил какую-то подзадачу или перешел в новое состояние:

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/locks/Condition.html

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top