Wie kann ich eine Abfolge von Verfahren in Java unterbrechen?
-
19-09-2019 - |
Frage
Ich habe eine Reihe von Verfahren, die nacheinander ausgeführt werden müssen, bis entweder alle ausgeführt werden oder eine bestimmte Bedingung erfüllt ist. Hier ist der grundlegende Code, der ausgeführt werden muss, bis eine Bedingung erfüllt ist:
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
}
Bisher habe ich nur daran gedacht, das zu tun, was ich wollte, folgendermaßen:
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
}
Das false
Parameter zu go()
und spin()
Zeigt an, dass sie sofort zurückkehren sollten, sodass die Bedingung überprüft wird. Dieser Ansatz fällt mir jedoch als eher ineffizient an, da der gleiche Codeblock 10 -mal wiederholt werden muss. Könnte dies mit Ausnahmen oder gleichzeitigen Threads effizienter erreicht werden?
Lösung
Basierend auf Jonathan Leffler's Antworten:
Sie können einen Runnable als verwenden Zeiger zu den Befehlen
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
}
Ein weiterer Schritt, falls zutreffend, setzen Sie die Befehle in einem Array oder einer Liste und führen Sie es als Skript aus
...
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 */);
}
Andere Tipps
Ich bin mir nicht sicher, warum Sie es verwenden Thread.yield()
- Gibt es andere Themen, die Sie nicht erwähnt haben? Oder vielleicht habe ich das Problem falsch verstanden.
Ich denke, vielleicht könnte das Befehlsmuster hier funktionieren. Sie hätten eine RobotCommand
Schnittstelle mit an execute
Methode und eine Implementierung von RobotCommand
pro Befehlstyp (Go, Spin usw.). Dann könntest du a konstruieren RobotAlgorithm
Als ein List
von RobotCommand
, und haben eine Methode executeRobotAlgorithm
das über die Liste iteriert, rufe an execute
auf jeder RobotCommand
und das Ergebnis von Überprüfen thingFound()
nach jedem.
Bearbeiten - Oh, ich glaube, ich verstehe es. Tun go
und spin
Fäden starten, die den Zustand des Roboters oder so etwas verändern?
Bearbeiten 2 - Als Antwort auf Ihren Kommentar klingt das Problem hier, dass Sie sofort zurückkehren müssen, wenn der Roboter findet, wonach er sucht, aber der go
, spin
, usw. Befehle werden dies momentan nicht tun, und Sie benötigen die Möglichkeit, in der Zwischenzeit weiterhin neue Befehle auszuführen. Ich könnte hier also zwei Threads haben - einer wäre ein "Executor" -Thread, der Ihre ausführen würde List
von RobotCommand
s einzeln und ein "Beobachter" -Faden, der wiederholt schlafen und abfragt thingFound()
). Wenn thingFound()
Ist jemals wahr, dann können Sie Ihren Roboter sowie den Executor -Thread stoppen oder wenn der Testamentsvollstrecker zuvor am Ende kommt thingFound()
Ist wahr, dann kann es als solche signalisieren (falls erforderlich).
Die while -Schleife kann eindeutig in seine eigene Funktion verpackt werden:
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
}
(Ich habe nichts dagegen, ob die Bedingung über zwei Zeilen geteilt wird. Ich würde das wahrscheinlich im Produktionscode tun.)
Ein besserer Java -Programmierer, als ich Ihnen sagen kann, ob Sie 'Verfahren' umgeben können (Hinweise auf Funktionen, in Bezug auf C -Programmierung). Ich vermute, Sie können, aber ich kenne die Syntax und die Regeln nicht. Das Beweis scheint zu sein, dass du nicht kannst (um 2004 sowieso).
Roboter kann ein Bedingungsobjekt verwenden, um dem Controller zu signalisieren, dass er einige Unteraufgaben abgeschlossen hat oder einen neuen Zustand eingegeben hat:
http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/locks/condition.html
interessant, für die Umgebung, in der Sie wahrscheinlich verwenden könnten und benachrichtigen() und Warten() anstelle des flexibleren Zustands. Controller könnte warten (), bis der Roboter beschließt, ihn mit Notify () freizulassen.