Ich habe ein großes Code-Segment, das keine Schleife ist, nur eine Liste von Befehlen, die einmal passiert, aber einige Zeit braucht. Ich brauche es entweder zu pausieren oder zu einem beliebigen Zeitpunkt zu beenden, basierend auf einem sich ändernden booleschen Wert. Ich könnte einen anderen Thread verwenden, um diesen Code zu suspendieren, fortzusetzen und zu stoppen, aber diese Methoden sind veraltet, weshalb ich sie vermeiden möchte. Ich könnte den Booleschen Wert zwischen jeder Codezeile überprüfen, aber ich hoffe auf eine elegantere Lösung. Gibt es einen guten Weg, dies zu tun?Alternative zu Thread.suspend() und .resume()
Antwort
Die korrekte Art, einen Thread zu unterbrechen (in diesem Fall, um ihn anzuhalten oder zu stoppen), ist natürlich Thread#interrupt()
. Es ist so konzipiert, dass Sie sichere Punkte definieren können, an denen der Thread unterbrochen werden kann, was für Sie natürlich der Punkt zwischen jeder Aufgabe ist. Um zu vermeiden, dass Sie Ihre Variablen zwischen den einzelnen Aufgaben manuell überprüfen müssen, können Sie Ihre Aufgaben einfach als eine Liste von Runnable
s speichern und Ihre Position in der Liste ab dem Zeitpunkt Ihrer Beendigung speichern , wie folgt:
public class Foo {
public static void runTask(Runnable task) throws InterruptedException {
task.run();
if (Thread.interrupted()) throw new InterruptedException();
}
Runnable[] frobnicateTasks = new Runnable[] {
() -> { System.out.println("task1"); },
() -> { Thread.currentThread().interrupt(); }, //Interrupt self only as example
() -> { System.out.println("task2"); }
};
public int frobnicate() {
return resumeFrobnicate(0);
}
public int resumeFrobnicate(int taskPos) {
try {
while (taskPos < frobnicateTasks.length)
runTask(frobnicateTasks[taskPos++]);
} catch (InterruptedException ex) {
}
if (taskPos == frobnicateTasks.length) {
return -1; //done
}
return taskPos;
}
public static void main(String[] args) {
Foo foo = new Foo();
int progress = foo.frobnicate();
while (progress != -1) {
System.out.println("Paused");
progress = foo.resumeFrobnicate(progress);
}
System.out.println("Done");
}
}
-->
task1
Paused
task2
Done
Ich stimme damit nicht überein. Interrupt hat das Problem, dass es ... im Grunde ... einige blockierende Operationen unterbricht und den unterbrochenen Thread in einem Zustand belässt, in dem die Wiederaufnahme (zumindest) kompliziert ist. Das Testen eines booleschen Werts ist ein besserer Ansatz für eine Pause/Wiederaufnahme. –
@StephenC Alle Blockierungsoperationen, die möglicherweise unterbrochen werden, erzwingen die Überprüfung auf InterruptedException und entscheiden, was zu tun ist. Es klingt für mich so, als ob sie solche Operationen verwenden würden, dann ist es das gewünschte Verhalten, sie zu unterbrechen (obwohl sie möglicherweise einige Mittel zur Signalisierung hinzufügen müssen, um taskPos nicht zu erhöhen); Wenn dies nicht das gewünschte Verhalten ist, können sie 'Thread.interrupted()' leicht durch eine spezielle Feldabfrage ersetzen. – Vitruvius
In diesem Fall möchte das OP suspend/resume, nicht unterbrechen/neu starten Semantik. Die Frage besagt, dass er nach einem Ersatz für 'Thread.suspend()' sucht, und so weiter. –
Sie können wait/notify als Alternative zum Suspend/Resume verwenden. Statt Stopp können Sie ein Flag setzen, mitteilen und eine Ausnahme von angemeldeten Thread werfen
Denken Sie daran, dass dies kein Code-Code ist. Es gibt keinen geeigneten Ort, an dem das Überprüfen einer Flagge oft geschieht. Wenn ich deine Lösung verstehe, hätte ich die Flagge jede zweite Zeile überprüft, an diesem Punkt könnte ich auch nur den Booleschen Wert überprüfen. – yesennes
Es gibt eine ausgezeichnete Dokumentation darüber, warum Thread.stop()
, Thread.pause()
und Thread.resume()
sind veraltet:
Java Thread Primitive Deprecation
Es gibt auch eine Alternative für /Thread.resume()
mit wait
und notify
erklärt.
Ich kann nicht denken, wie man in meiner Situation warte und benachrichtige. Wenn Sie können, würde ich mich freuen zu wissen. – yesennes
@yesennes Siehe die Antwort https://stackoverflow.com/questions/28922040/alternative-to-thread-suspend-and-resume/45786529#45786529, um dies mithilfe von wait/notify zu tun. – zafar142003
Ich könnte den Boolean zwischen jeder Codezeile überprüfen, aber ich hoffe auf eine elegantere Lösung. Gibt es einen guten Weg, dies zu tun?
Leider nein.
Um Pause/Resume zu ersetzen, ist es wichtig, dass ein Thread einen anderen Thread "pausiert", ohne den Code des zweiten Threads zu verwenden.
Dies ist in Java nicht möglich, wie es derzeit spezifiziert und implementiert ist.
Die veralteten Thread-Methoden sind die einzige Möglichkeit, einen Thread zu beenden, zu stoppen/anzuhalten, einen anderen Thread fortzusetzen ... wenn der andere Thread nicht aktiv kooperiert. Sie waren veraltet, weil (in Kürze) diese Art von Kontrolle nicht in jeder gängigen Generation Mainstream JVM sicher implementiert werden kann.
Das Beste, was Sie tun können, ist das Umbrechen der Logik für Pause/Fortsetzen in einer Methode, die der zweite Thread an geeigneten Punkten aufruft. (Dies sollte wahrscheinlich warten/benachrichtigen ... oder gleichwertig ... um die Wiederaufnahme zu behandeln. Aber warten/notify per se adressiert nicht Ihre klare Anforderung zum Anhalten/Fortsetzen eines nicht kooperierenden Threads.)
1 - Sie benötigen etwas wie die Isolates-API, um dies zu tun. Es gab Versuche, es in Forschungsprojekten umzusetzen, aber AFAIK Isolates wurde nie in einer Produktions-JVM implementiert.
Bitte erläutern Sie den Downvote. Sie mögen diese Antwort nicht * mögen *, aber die Ablehnung wird die Realität nicht ändern. Java bietet Ihnen keine wesentlich bessere Alternative als die, die Sie gerade verwenden. –
Das war ein Miss Klick. Ich wollte es abstimmen. Ich mochte die Antwort nicht, aber sie war wahr und auf meine Situation anwendbar. Ich hätte mich jetzt darum kümmern müssen. – yesennes
Es gibt eine ungefähre Lösung für dieses Problem. Bitte beachten Sie die Antwort https://stackoverflow.com/questions/28922040/alternative-to-thread-suspend-and-resume/45786529#45786529 – zafar142003
Ich habe eine Idee, wie Sie dies mit AspectJ tun.Die Lösung, die ich unten skizziere, erlaubt Ihnen, einen anderen Thread anzuhalten/fortzusetzen. Diese Pause tritt erst beim nächsten Methodenaufruf aus der Zielmethode in Kraft, nachdem Sie die Pause-Routine aufgerufen haben. Dies wird nicht erfordern boolesche Überprüfungen nach jeder Zeile des Codes Ihrer Zielmethode. Ich verwende wait/notify, um dies zu tun.
Ich verwende Spring in dem folgenden Beispiel.
Zuerst wickeln Sie Ihre Zielmethode in eine ausführbare Datei.
Als nächstes machen Sie einen Aspekt, der bei jedem Methodenaufruf innerhalb Ihrer Zielmethode bedingt aufgerufen würde.
@Aspect
@Component
public class HandlerAspect {
public static volatile boolean stop=false;
public static volatile String monitor="";
@Pointcut("withincode(public void com.app.inter.thread.communication.runnables.TestRunnable.run()) "
+ "&& call(* *.*(*)) "
+ "&& if()")
public static boolean stopAspect(){
return stop;
}
@Before("stopAspect()")
public void beforeAdvice(JoinPoint jp) {
try {
System.out.println("Waiting");
synchronized(monitor){
monitor.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
stop=false;
}
}
Nun, wenn Sie Ihren Thread zu unterbrechen wollen, setzen Sie einfach den Wert von stop
zu wahren, und umgekehrt.
@Service
public class Driver {
@Autowired
private HandlerAspect aspect;
@PostConstruct
public void init(){
Scanner scanner = new Scanner(System.in);
int i=-1;
TestRunnable runnable = new TestRunnable();
Thread thread= new Thread(runnable);
thread.start();
aspect.monitor="MONITOR";
while((i=scanner.nextInt())!=0){
switch(i){
case 1:
aspect.stop=true;
break;
case 2:
aspect.stop=false;
synchronized(aspect.monitor){
aspect.monitor.notify();
}
break;
}
}
// in case the main thread is stopped
// while the other thread is in wait state
synchronized(aspect.monitor){
aspect.monitor.notify();
}
thread.interrupt();
}
}
Die Ausgabe ist wie folgt:
...
Working 400000001
1Working 410000001
Working 420000001
Working 430000001
Working 440000001
Working 450000001
Working 460000001
Working 470000001
Waiting
2
Working 480000001
Working 490000001
0
Arbeitscode ist bei https://github.com/zafar142007/InterThreadCommunication
- 1. Unterschied zwischen Thread.Abort() und Thread.Suspend()?
- 2. Resume PHP zu Ausführungsskript nach Ausnahme
- 3. pause und resume setInterval in Javascript
- 4. Sovren Resume Parser - Python
- 5. App resume Zustand auf iOS und Android
- 6. Resume Count in IsolatedStorageSettings
- 7. Benachrichtigung Resume Aktivität
- 8. C# Bei Fehler resume
- 9. Resume Activity from Fragment
- 10. Pause/Resume http Verbindung Download
- 11. Pausieren & Resume Android Repo Sync
- 12. Eine Alternative zu Flex und Bison Duo?
- 13. Alternative zu tlsAlloc tlsGetValue und tlsSetValue
- 14. Resume-Jobs können keine Verbindung zu externen Hosts herstellen
- 15. Alternative zu SlideshowPro Director?
- 16. Alternative zu Tiny MCE
- 17. Alternative zu pcap (Linux)
- 18. vb.net winform downloader pause und resume funktioniert nicht richtig
- 19. Alternative zu Files.probeContentType?
- 20. Alternative zu Cookies
- 21. Sichere Alternative zu Teilsätzen?
- 22. Alternative zu Breeze.js?
- 23. Alternative zu exec
- 24. Alternative zu pthread_timedjoin_np
- 25. Alternative zu NSFetchedResultsController?
- 26. Alternative zu TXMLDocument?
- 27. Alternative zu Fiddler?
- 28. Alternative zu immintrin.h
- 29. Alternative zu Dreamweaver?
- 30. Alternative zu Flex Framework
Wie werden Sie jeden Befehl ausführen? Wenn das eine separate Klasse wie "Action" oder "Command" ist, können Sie dort den Check durchführen. Ansonsten kann man nicht viel tun ... wie in anderen Antworten geschrieben. – Jayan
Ich bin Code-unabhängig für einen FRC-Roboter. Einiges davon ist es, die Motoren auf eine Geschwindigkeit zu setzen und zu warten, andere Bits sollen die Motorwerte einstellen, bis die Sensoren einen bestimmten Wert ergeben. – yesennes