2009-07-22 5 views
4

S'il vous plaît se référer à UMLQuel objet devrais-je verrouiller lorsque je passe une collection <Foo> dans une classe séparée?

Le constructeur de la classe Connection initialise ses foos membre via

foos = Collections.synchronizedList(new ArrayList<Foo>(10)); 

Lorsque la connexion # start() est appelée, elle crée une instance de Poller (en passant les foos référence dans le constructeur de Poller) & Poller est démarré (Poller est un Runnable).

Question: Le fil Poller va ajouter à & objets supprimer de la liste en fonction des événements extérieurs. Périodiquement, les clients appellent Connection # snapshot() pour récupérer la liste. Étant donné que l'implémentation dans Poller effectuera une vérification pour éviter les doublons lors des ajouts, elle n'est pas sécurisée pour les threads.

par exemple. # Poller Application de l'exécution

if(_foos.indexOf(newFoo) == -1) 
{ 
    _foos.add(newFoo); 
} 

Que puis-je synchroniser dans Connexion ainsi que Poller à l'ordre d'être thread-safe?

+0

Vous pouvez intégrer des images dans votre question, vous n'avez pas besoin d'utiliser un lien externe. –

Répondre

0

Vous pouvez retourner une nouvelle liste de snapshot():

public List<Foo> snapshot() { 
    return new ArrayList<Foo>(foos); 
} 

Étant donné que vous retournez un « instantané », il me semble bien que la liste est garanti que la mise à jour à le moment où il est retourné.

Si vous attendez des clients qu'ils ajoutent/suppriment des membres de foos, vous devrez probablement exposer ces opérations en tant que méthodes sur Connection.

+0

Les clients ne sont pas autorisés à ajouter/supprimer de l'instantané. –

1

Jetons un oeil à CopyOnWriteArrayList en remplacement de ArrayList dans l'exemple ci-dessus. De cette façon, vous ne serez pas besoin de synchroniser quoi que ce soit puisque vous avez un fil collection en toute sécurité hors de la boîte, pour ainsi dire ...

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/CopyOnWriteArrayList.html

De l'API CopyOnWriteArrayList est ...

Une variante thread-safe de ArrayList dans que toutes les opérations mutatives (ajouter, définir, et ainsi de suite) sont implémentées par faisant une nouvelle copie du tableau sous-jacent.

n.b. Ce n'est qu'une solution viable si le nombre de traversées l'emporte sur le nombre d'ajouts/mises à jour de la collection. Est-ce le cas?

1

Il existe une solution propre utilisant des interfaces et des classes internes anonymes.

Dans la Connexion classe ajouter ce qui suit:

public static interface FooWorker { 
    void onFoos(List<Foo> list); 
} 

public synchronized void withFoosSafely(FooWorker worker) { 
    worker.onFoos(foos); 
} 

Dans le Poller classe procédez comme suit:

public void doWork() { 
    connection.withFoosSafely(new FooWorker() { 
     public void onFoos(List<Foo> list) { 
       /// add, remove and change the list as you see fit 
       /// everything inside this method is thread-safe 
     } 
    }); 
} 

Il faut un peu de code supplémentaire (pas de fermeture encore Java), mais cela garantit la sécurité des threads et garantit que les clients n'auront pas besoin de se préoccuper des éventuels bugs potentiels.

0

Peut-être que je ne reçois pas le point, il semble Connection#snapshot doit être synchronisé sur this (ou sur _foos), et ne le bloc de code de Poller qui gère Connection._foos.

Qu'est-ce qui me manque?

+0

Poller est une classe distincte, ce n'est pas une classe interne de connexion! –

+0

Cela ne l'empêche pas d'avoir un bloc synchronisé sur Connection. Je suis sûr qu'il a une référence au gestionnaire de connexion, sinon comment pourrait-il gérer? –

Questions connexes