2009-08-12 5 views
3

Ich habe zwei Threads von einer Controller-Klasse ausgeführt. Der erste Thread empfängt SMS-Nachrichten und sollte weiter ausgeführt werden, solange das Programm im gestarteten Zustand ist. Der andere Thread wird verwendet, um den GPS-Standort der Einheiten zu berechnen.Wie (d) Methoden zu synchronisieren und Eigenschaften von Objekten in einem übergeordneten Objekt zu ändern?

Der Controller startet den SMS-Thread und wartet auf eine Textnachricht. Wenn eine Textnachricht bestimmte Kriterien erfüllt, wird der GPS-Standort-Thread gestartet und die Koordinaten werden zurück an die Steuerung gesendet.

Für jeden Thread, habe ich folgendes Format verwendet:

reader = new Reader(this); 
     new Thread(reader).start(); 

Der Leser Klasse verwendet dann eine Referenz der Steuerung, so dass es ein Verfahren, in dem Controller nennen kann:

public void ReceivedCommand(String address) { 
    [..] 
} 

Diese Methode erstellt dann eine Instanz des GPS-Threads, der selbst eine Methode aus dem übergeordneten Objekt (Thread?) Namens ReceivedLocation aufruft, die dann die neue SMS-Nachricht (TextMessage Objekt) einrichtet. Das Problem ist, dass der SMS-Thread nur die Adresse des ursprünglichen Absenders zurückgeben kann (um darauf zu antworten), und ich muss den GPS-Thread verwenden, damit ich die Payload für die SMS-Nachricht einstellen kann.

So jetzt habe ich 2 Methoden mit dem gleichen Objekt (TextMessage Objekt), aber ich möchte sicherstellen, dass die erste Methode (SMS-Adresse Setter) die Adresse nicht ändert, während der GPS-Thread die GPSLocation zu setzen bekommt.

kann ein Block innerhalb ReceivedCommand() Synchronisierung:

  • die Adresse zum Objekt TextMessage hinzufügen,
  • den Faden GPS Lauf
  • Lassen Sie das GPS-Thread die zweite Methode aufrufen (ReceivedLocation())
  • Und Lassen Sie diese Methode das TextMessage-Objekt ändern?
+0

ich meine Antwort über 50 bearbeitet haben jetzt mal - wahrscheinlich einen weiteren gelesen Wert. Beachten Sie, dass das Synchronisieren der Methoden Ihres 'TextMessage'-Objekts nicht immer ausreicht - es können * atomare * Operationen vorhanden sein, die Sie steuern möchten (d. H. Ein' compareAndSet') –

Antwort

4

Erstens ist die Erstellung von Threads teuer. Sie könnten besser sein, einen Thread-Pool mit (wie im java.util.concurrent Paket gefunden werden kann (ein ExecutorService) und Ihre Arbeit, die sicherstellen Mit synchronized auf ein gemeinsam genutzten Objekt

Landwirtschaft ab, dass keine zwei Fäden sein können . Innere a synchronized Block zugleich jedoch, wenn ich einen Thread in einem synchronized Block erstellen und starten, I (dh den ersten Thread), um den Block verlassen haben kann, bevor der zweite Thread tatsächlich beginnt:

final TextMessage msg = //... 
Thread t = new Thread(r); 
synchronized (msg) { 
    t.start(); 
} //the other thread is still running and now this thread has not synchronized on the msg 

Dann Prozessor r:

Runnable r = new Runnable() { 
    public void run() { 
     synchronized (msg) { //only any use if readers are alse sync-ed 
      msg.setGpsLocation(findGpsLocation(msg)); 
     } 
    } 
} 

Solange das Objekt TextMessage threadsicher ist (d.h. Feldzugriff ist synchronized) sollten Sie in Ordnung sein und gibt es keine Notwendigkeit, auf diese Weise explizit zu synchronisieren.

Beachten Sie, dass synchronized semantisch wichtig ist, nicht nur aus der Perspektive der fadenPlanung, sondern auch aus der Tatsache, dass it affects data visibility between threads (zum Beispiel ohne Synchronisation, können Sie nicht sicher sein, dass in einem Thread vorgenommenen Änderungen sichtbar sein zum anderen).

meine Antwort Ändern eines ExecutorService zu verwenden: Hier

final TextMessage msg = //... 
ExecutorService worker = Executors.newSingleThreadedExecutor(); 
Future<?> f = worker.submit(r); //the future represents the work 

, r würde wie folgt aussehen:

Runnable r = new Runnable() { 
    public void run() { 
     GpsLocation loc = findGpsLocation(msg); 
     msg.setGpsLocation(loc); //the setter is synchronized 
    } 
} 

Es ist die setGpsLocation Methode, die synchronized (zusammen mit dem getter sein sollte und jeder andere Feldzugriff wird von beiden Threads benötigt). Beachten Sie, dass das Synchronisieren des Feldzugriffs nicht immer ausreicht, wenn Sie die Atomizität über Felder hinweg benötigen. Zum Beispiel können Sie ein Feld bedingt auf den Wert eines anderen aktualisieren - in diesem Fall so lange, wie Sie während der Feldzugriff explizit synchronize, alles in Ordnung sein wird:

synchronized (msg) { 
    if (msg.getGpsLocation().isIn(AMERICA)) 
     msg.append(" DUDE!") 
} 
Verwandte Themen