Как я могу прервать последовательность процедур в Java?
-
19-09-2019 - |
Вопрос
У меня есть куча процедур, которые необходимо выполнять последовательно, пока либо все они не будут выполнены, либо не будет выполнено определенное условие.Вот базовый код, который необходимо выполнять до тех пор, пока не будет выполнено условие:
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
из RobotCommand
s один за другим, и поток "наблюдателя", который будет неоднократно переходить в спящий режим и опрашивать (проверьте 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().