2016-06-16 9 views
0

Ich muss viele Hintergrund-Threads verwalten, die etwas mit einigen Objekten als Schlüssel tun, aber nur ein Thread kann mit demselben Objekt zur gleichen Zeit arbeiten, zum Beispiel während thread A arbeitet an object A arbeitet, Wenn thread B zum Arbeiten mit object A aufgerufen wird, sollte thread A abgebrochen werden, bevor thread B ausgeführt werden kann.Implementieren Sie einen Abbrechen Thread-Manager für ein eindeutiges Objekt

Hier ist mein Code, aber wenn ich laufe, Der erste Thread nicht stoppen und setzt sich mit zweiten:

private static ExecutorService mExecutor = Executors.newCachedThreadPool(); 
private static ConcurrentMap<Object, Future> mRunningTasks = new ConcurrentHashMap<>(); 
public static void run(final Runnable runnable, final Object key) { 
    Future<?> future = mRunningTasks.get(key); 
    if (future != null) { 
     future.cancel(true); 
    } 
    future = new FutureTask<>(new Runnable() { 
     @Override 
     public void run() { 
      //How to handle InterruptedException here ? 
      //while there's no potential to throw an InterruptedException 
      runnable.run(); 
      mRunningTasks.remove(key); 
     } 
    }, null); 
    mRunningTasks.put(key, future); 
    mExecutor.execute((FutureTask) future); 
} 

Was soll ich hier fehlt?

Vielen Dank im Voraus.

PS: Ich brauche ein Verhalten wie Picasso API, wenn Anforderungen Bricht eine ImageView als Schlüssel-Objekt.

+0

Verwenden Sie RxJava für das –

Antwort

0

Die Dokumente für Future.cancel() sagen, dass es versucht, die Aufgabe abzubrechen, aber möglicherweise nicht erfolgreich ist. Sie müssen den booleschen Rückgabewert überprüfen, um zu sehen, ob er tatsächlich abgebrochen wurde.

+0

Hey, Danke für die Antwort, wenn ich nicht den Rückgabewert verwechselt zeigt nur die Operation Ergebnis, obwohl, wenn ich logge, das Ergebnis ist wahr, aber der Thread läuft weiter, Was ich frage ist wie und wo Ich kann das lauffähige Objekt stoppen? –

+0

Sie können einen laufenden Thread in Java nicht töten (gut, aber es ist eine sehr schlechte Übung). Der richtige Weg besteht darin, eine volatile boolesche Variable zu Ihrer Instanz zu setzen, um sie zu bitten, die Verarbeitung zu beenden. Die ThreadPools sind für kurzlebige laufende Threads gedacht. –

+0

@GuillaumeF. Ich bekomme, was Sie vorschlagen, Überprüfen Sie die Bedingung in einer Schleife, aber auf die erste Wiederholung der gesamte Code in Runnable wird ausgeführt Wenn Sie verstehen, was ich meine –

0

Es gibt mehrere andere Raceconditions in Ihrem Code.

ConcurrentHashMap ist Threadssafe, aber die Art, wie Sie es verwenden, ist nicht. Sie könnten: * Abbrechen Zukunft mehrmals * eine Zukunft hinzugefügt werden, ohne die vorherige * Löschen der falschen Futures von der Karte entfernen

Sie sollten genauer sein über Sie wollen tatsächlich lösen. Es könnte bessere Lösungen für dieses Problem geben.

0

Sie wollen den Thread (Thread.stop()) töten, die eine sehr schlechte Praxis ist und aus vielen Gründen veraltet ... Nicht nur für keine Verantwortung über den Thread, da es von der ThreadPool verwaltet wird, aber töten Es ruiniert das Konzept der Atomizität Ihres Algorithmus und lässt Ihre Software in einem möglicherweise unbestimmten Zustand.

Sie können eine FutureTask abbrechen, wenn sie nicht gestartet wurde. Wenn Sie es nicht abbrechen können, bedeutet dies, dass es bereits ausgeführt wird. Dies geschieht auf modernen Multi-Core-Prozessoren unglaublich schnell.

Die ThreadPool ist normalerweise für kurzlebige laufende Threads gedacht. Aber in Ihrem Fall ist der richtige Weg, um die Aufgabe richtig zu beenden, eine volatile boolean Variable in Ihrer Task-Klasse zu setzen und sie regelmäßig zu überprüfen, um die Methode zu verlassen.

InterruptedException wird nur ausgelöst, wenn Ihr Thread wartet oder schläft, die in Ihrem aktuellen Demo-Code nicht vorhanden ist. Wenn Ihr Thread tatsächlich wartet oder schlafen, dann eine .notify() an den Monitor Objekt senden Sie es, zu unterbrechen und die Exception in einem try {} catch()

0

Es gibt zwei primäre Probleme hier 1) die run-Methode muss deklariert werden, fangen synchronisiert (Vermeidet Race Conditions bei der Überprüfung des Zustandes) und 2) future.cancel ist nicht in der Lage, begonnene Arbeiten zu stoppen. Fügen Sie also Ihren Runnables Ihre eigenen Wachen/Abbruchmechanismen hinzu.

Das heißt, die sauberste Lösung ist es, die Notwendigkeit zu vermeiden, an erster Stelle zu vermeiden, aber es gibt nicht genug Domain-Detail in dieser Frage, um zu überprüfen, ob dies machbar wäre. Ein übliches Muster für diese Art von Problem besteht darin, ein Versprechen aus dem Lauf zurückzugeben und die Versprechen zwischenzuspeichern. Ein Versprechen ist ein threadsicheres Containerobjekt für das Ergebnis eines asynchronen Vorgangs. Wenn die gleiche Arbeit zweimal geplant wird, kann dasselbe Versprechen zurückgegeben werden. Wenn ein Versprechen einen Wert hat, wäre es möglich zu sehen, wie alt der Wert war, um das Planungsverhalten zu bestimmen, wie den alten Wert zurückzugeben, den alten Wert zurückzugeben und eine Aktualisierung des Wertes hinter den Kulissen zu planen oder den alten Wert wegzuwerfen als zu alt und hol einen sauberen Wert.

Verwandte Themen