Question

Je dois sécuriser un thread ArrayList of ArrayLists. Je ne peux pas non plus que le client modifie la collection. Le wrapper non modifiable le rendra-t-il sûr ou ai-je besoin de deux wrappers dans la collection?

Était-ce utile?

La solution

Cela dépend. Le wrapper empêchera uniquement les modifications apportées à la collection qu'il enveloppe, pas aux objets de la collection. Si vous avez une ArrayList of ArrayLists, la liste globale ainsi que chacune de ses listes d'éléments doivent être emballées séparément et vous devrez peut-être également modifier le contenu de ces listes. Enfin, vous devez vous assurer que les objets de la liste d'origine ne sont pas modifiés, car le wrapper empêche uniquement les modifications via la référence du wrapper, et non à l'objet d'origine.

Dans ce cas, vous n'avez PAS besoin du wrapper synchronisé.

Autres conseils

Sur un sujet connexe - J'ai vu plusieurs réponses suggérant l'utilisation de la collecte synchronisée afin d'assurer la sécurité des threads. L'utilisation de la version synchronisée d'une collection ne la rend pas "thread safe". - bien que chaque opération (insert, count, etc.) soit protégée par mutex lors de la combinaison de deux opérations, rien ne garantit qu'elles s'exécuteraient de manière atomique. Par exemple, le code suivant n'est pas thread-safe (même avec une file d'attente synchronisée):

if(queue.Count > 0)
{
   queue.Add(...);
}

Le wrapper non modifiable empêche uniquement les modifications de la structure de la liste à laquelle il s'applique. Si cette liste contient d'autres listes et que des threads tentent de modifier ces listes imbriquées, vous n'êtes pas protégé contre les risques de modification simultanée.

En regardant la source Collections, il semble que l'option Non modifiable ne soit pas synchronisée.

static class UnmodifiableSet<E> extends UnmodifiableCollection<E>
                 implements Set<E>, Serializable;

static class UnmodifiableCollection<E> implements Collection<E>, Serializable;

les wrappers de classe synchronisés ont un objet mutex pour créer les parties synchronisées. Il semble donc que vous deviez utiliser les deux pour obtenir les deux. Ou roulez les vôtres!

Je pense que, puisque l'encapsuleur UnmodifiableList stocke l'ArrayList dans un champ final, toutes les méthodes de lecture de l'encapsuleur verront la liste telle qu'elle était lors de la construction de l'encapsuleur tant que la liste n'est pas modifiée après sa création. et tant que les ArrayLists mutables à l'intérieur du wrapper ne sont pas modifiés (ce que le wrapper ne peut pas protéger).

Si la vue non modifiable est publiée en toute sécurité et si l'original modifiable n'est jamais modifié (y compris tous les objets contenus récursivement dans la collection!) après la publication de la vue non modifiable,

Si vous souhaitez continuer à modifier l'original, vous pouvez créer une copie défensive du graphe d'objets de votre collection et renvoyer une vue non modifiable de celle-ci, ou utiliser une liste intrinsèquement sécurisée pour les threads, puis renvoyer une vue non modifiable de cela.

Vous ne pouvez pas renvoyer une liste non modifiable (synchonizedList (theList)) si vous souhaitez toujours accéder à la liste non synchronisée ultérieurement; si l'état mutable est partagé entre plusieurs threads, tous les threads doivent se synchroniser sur les verrous identiques lorsqu'ils accèdent à cet état.

Un objet immuable est par définition thread-safe (en supposant que personne ne conserve les références aux collections d'origine), la synchronisation n'est donc pas nécessaire.

Emballage de la liste de tableaux externe à l'aide de Collections.unmodifiableList () empêche le client de changer son contenu (et donc le rend thread sûr), mais les tableaux internes sont toujours modifiables.

Emballage des listes de tableaux internes à l'aide de Collections.unmodifiableList () aussi empêche le client de modifier son contenu (et donc le rend thread safe), ce dont vous avez besoin.

Indiquez-nous si cette solution pose des problèmes (surcharge, utilisation de la mémoire, etc.). d'autres solutions peuvent être applicables à votre problème. :)

EDIT: Bien sûr, si les listes sont modifiées, elles ne sont pas thread-safe. J'ai supposé qu'aucune autre modification ne devait être faite.

Je ne sais pas si j'ai bien compris ce que vous essayez de faire, mais je dirais que dans la plupart des cas, la réponse est "Non".

Si vous configurez une ArrayList de ArrayList et que les deux, les listes interne et externe ne peuvent plus être modifiées après la création (et lors de la création, un seul thread aura accès aux listes interne et externe), elles sont probablement sécurisées pour les threads par un wrapper. (si les deux listes internes et externes sont encapsulées de telle manière qu'il est impossible de les modifier). Toutes les opérations en lecture seule sur ArrayLists sont très probablement thread-safe. Cependant, Sun ne garantit pas qu'ils sont sécuritaires pour les threads (pas plus pour les opérations en lecture seule). Par conséquent, même si cela peut fonctionner à présent, cela pourrait se rompre à l'avenir (si Sun crée des modifications internes). mise en cache des données pour un accès plus rapide, par exemple).

Cela est nécessaire si:

  1. Il y a toujours une référence à la liste modifiable d'origine.
  2. La liste sera éventuellement accessible via un itérateur.

Si vous avez l'intention de lire ArrayList par index uniquement, vous pouvez supposer qu'il s'agit d'un thread-safe.

En cas de doute, choisissez le wrapper synchronisé.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top