2009-08-12 10 views
3

J'ai deux threads en cours d'exécution à partir d'une classe de contrôleur. Le premier thread reçoit des messages SMS et doit continuer à s'exécuter tant que le programme est dans l'état démarré. L'autre thread est utilisé pour calculer l'emplacement GPS des unités.Comment synchroniser les méthodes (d) et modifier les propriétés des objets dans un objet parent?

Le contrôleur lance le thread SMS et attend d'un message texte. Si un message texte répond à certains critères, le fil de localisation GPS est lancé et les coordonnées sont renvoyées au contrôleur.

Pour chaque fil, je l'ai utilisé le format suivant:

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

La classe de lecteur utilise alors une référence du contrôleur afin qu'il puisse appeler une méthode dans le contrôleur:

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

Cette méthode crée ensuite une instance du thread GPS qui appelle lui-même une méthode de l'objet parent (thread?) Appelé ReceivedLocation qui configure ensuite le nouveau message SMS (objet TextMessage). Le problème est que le thread SMS ne peut que retourner l'adresse de l'expéditeur d'origine (pour répondre à) et j'ai besoin d'utiliser le fil GPS afin que je puisse définir la charge utile pour le message SMS. Donc maintenant j'ai 2 méthodes utilisant le même objet (TextMessage objet), mais je veux m'assurer que la première méthode (l'adresse d'adresse SMS) ne change pas l'adresse pendant que le thread GPS obtient le GPSLocation à définir.

peut synchroniser un bloc dans ReceivedCommand():

  • Ajouter l'adresse à l'objet TextMessage,
  • Exécutez le fil GPS
  • Laissez le fil GPS appeler la deuxième méthode (ReceivedLocation())
  • Et laissez cette méthode modifier l'objet TextMessage?
+0

J'ai modifié ma réponse 50 fois maintenant - vaut probablement une autre lecture. Notez que la synchronisation des méthodes de votre objet 'TextMessage' n'est pas toujours suffisante - il peut y avoir des opérations * atomic * que vous voulez contrôler (c'est-à-dire' compareAndSet') –

Répondre

4

Premièrement, la création de threads est coûteuse. Vous pourriez être mieux d'utiliser un pool de threads (comme on peut le trouver dans le paquetage java.util.concurrent (un ExecutorService) et l'agriculture de votre travail à ce

En utilisant synchronized sur un objet partagé veillera à ce qu'aucun deux fils peuvent être . a l'intérieur un synchronized bloc en même temps Cependant, si je crée et commence un fil dans un synchronized bloc, je (le premier fil) peut-être quitté le bloc avant le second fil commence réellement:

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 

Ensuite, votre processeur r:

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

Tant que l'objet TextMessage est thread-safe (à savoir l'accès au champ est synchronized) vous devriez être OK et il n'est pas nécessaire de synchroniser explicitement de cette manière.

Notez que synchronized est sémantiquement important non seulement du point de vue du fil planification, mais aussi du fait que it affects data visibility between threads (par exemple, sans synchronisation, vous ne pouvez pas être sûr que les modifications apportées dans un thread seront visibles à un autre).

Modifier ma réponse à utiliser un ExecutorService:

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

Ici, r ressemblerait à ceci:

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

Il est la méthode setGpsLocation qui devrait être synchronized (avec le getter et tout autre accès au champ requis par les deux threads). Notez que la simple synchronisation de l'accès aux champs n'est pas toujours suffisante si vous avez besoin d'atomicité entre les champs. Par exemple, vous voudrez peut-être mettre à jour un champ conditionnellement à la valeur d'une autre - dans ce cas, aussi longtemps que vous synchronize explicitement lors de l'accès sur le terrain, tout sera OK:

synchronized (msg) { 
    if (msg.getGpsLocation().isIn(AMERICA)) 
     msg.append(" DUDE!") 
} 
Questions connexes