Question

Je l'ai lu dans un peu, mais ne l'ai pas trouvé une réponse définitive.

J'ai une classe qui ressemble à ceci:

    public class Foo() {

        private static final HashMap<String, HashMap> sharedData;

        private final HashMap myRefOfInnerHashMap;

        static {
           // time-consuming initialization of sharedData
           final HashMap<String, String> innerMap = new HashMap<String, String>;
           innerMap.put...
           innerMap.put...
           ...a

           sharedData.put(someKey, java.util.Collections.unmodifiableMap(innerMap));
        }

        public Foo(String key) {
            this.myRefOfInnerHashMap = sharedData.get(key);
        }

        public void doSomethingUseful() {
            // iterate over copy
            for (Map.Entry<String, String> entry : this.myRefOfInnerHashMap.entrySet()) {
                ...
            }
        }
     }

Et je me demande si elle est thread-safe pour accéder shareddata des instances de Foo (comme le montre le constructeur et doSomethingUseful ()). De nombreux cas de Foo seront créés dans un environnement multi-thread.

Mon intention est que shareddata est initialisé dans l'initialiseur statique et non modifié par la suite (en lecture seule).

Ce que j'ai lu est que les objets immuables sont thread à sécurité intrinsèque. Mais je ne l'ai vu cela dans ce qui semble être le contexte des variables d'instance. Sont variables statiques immuables thread-safe?

L'autre construction que j'ai trouvé un ConcurrentHashMap. Je pourrais faire shareddata de type ConcurrentHashMap mais ne les HashMaps qu'il contient aussi être de type ConcurrentHashMap? En gros ..

private static final ConcurrentHashMap<String, HashMap> sharedData;

ou

private static final ConcurrentHashMap<String, ConcurrentHashMap> sharedData;

Ou serait-il plus sûr (encore plus cher simplement clone ())?

this.myCopyOfData = sharedData.get(key).clone();

TIA.

(initialiseur statique a été modifié pour donner plus de contexte.)

Était-ce utile?

La solution

référence pour sharedData qui est final est thread-safe car il ne peut jamais être changé. Le contenu de la carte est pas thread-safe, car il doit être soit enveloppé avec de préférence une mise en œuvre de ImmutableMap goyave ou java.util.Collections.unmodifiableMap() ou utilisez l'une des implémentations de carte dans le paquet java.util.concurrent.

Seulement si vous faites DEUX vous avez la sécurité de fil complet sur la carte. Tous les contenus doivent être carte immuable ou l'une des implémentations simultanées ainsi.

.clone () est fondamentalement cassé, rester à l'écart

clonage par défaut est un clone peu profond, il va juste retourner des références à des objets conteneurs non copies complètes. Il est bien documenté dans l'information généralement disponibles sur les raisons.

Autres conseils

Initialisation des champs statiques finales dans un bloc d'initialisation statique est thread-safe. Cependant, rappelez-vous que l'objet auquel un point de référence finales statiques peuvent pas être thread-safe. Si l'objet auquel vous faites référence est thread-safe (par exemple, il est immuable), vous êtes en clair.

Chaque HashMap individuelle contenue dans votre HashMap extérieure n'est pas garanti comme sûrs sauf si vous utilisez ConcurrentHashMap comme suggéré dans votre question. Si vous n'utilisez pas un HashMap intérieur thread-safe mise en œuvre, vous pouvez obtenir des résultats inattendus lorsque deux threads accèdent à la même HashMap intérieure. Gardez à l'esprit que seules certaines opérations sur ConcurrentHashMap sont synchronisées. Par exemple, l'itération n'est pas thread-safe.

Qu'est-ce que thread-safe? Bien sûr, l'initialisation du HashMap est thread-safe dans le respect que partagent la même instance de la carte de tous les Foo, et que la carte est garantie d'être là, à moins qu'une exception se produit dans l'initialisation statique.

Mais modifier le contenu de la carte est assurément pas thread-safe. finale statique signifie que la carte shareddata ne peut pas être changé pour une autre carte. Mais le contenu de la carte est une autre question. Si une clé donnée est utilisée plus d'une fois en même temps, vous pouvez obtenir des questions de concurrence.

Non. Sauf si elles sont immuables.

La seule chose qu'ils font est

  • Soyez niveau de la classe accesible
  • Évitez la référence à modifier.

Mais si votre attribut est mutable alors il est pas thread-safe.

Voir aussi: Est-ce que nous synchronisons variables instances qui sont définitives?

Il est exactement le même, sauf qu'ils sont au niveau de la classe.

Oui, c'est thread-safe trop. Tous les derniers membres de votre classe statique seront initialisés avant que thread est autorisé à y accéder.

Si le bloc de static échoue lors de l'initialisation, un ExceptionInInitializerError sera élevé dans le fil d'initialisation que les premières tentatives. tentative ultérieure de faire référence à la classe soulèvera un NoClassDefFoundError.

En général, le contenu d'un HashMap ont aucune garantie de visibilité sur les discussions. Cependant, le code d'initialisation de classe utilise un bloc de synchronized pour empêcher plusieurs threads de l'initialisation de la classe. Cette synchronisation videra l'état de la carte (et les instances de HashMap qu'il contient), de sorte qu'ils soient correctement visibles à toutes les discussions en supposant qu'aucun changement sont apportées à la carte ou les cartes qu'il contient, en dehors de la initialiseur de classe.

Voir la spécification du langage Java, § 12.4.2 pour des informations sur l'initialisation de la classe et l'exigence pour la synchronisation.

Il n'y a rien enfilez à sécurité intrinsèque sur une variable final static. Déclarer une variable membre final static assure seulement que cette variable est affectée à une seule fois.

La question de la sécurité des threads a moins à voir avec la façon dont vous déclarez les variables, mais repose plutôt sur la façon dont vous interagissez avec les variables. Donc, ce n'est pas vraiment possible de répondre à votre question sans plus de détails sur votre programme:

  • Ne plusieurs threads modifier l'état de votre variable sharedData?
  • Si oui, vous synchronisez sur tous les faire enregistrer ( et lit) de sharedData?

L'utilisation d'un ConcurrentHashMap ne garantit que les méthodes individuelles du Map sont thread-safe, il ne fait pas une telle opération thread-safe:

if (!map.containsKey("foo")) {
    map.put("foo", bar);
}

ne sont pas entre vous demandent en fait si l'initialisation statique de sharedData est thread-safe et exécutée une seule fois?

Et oui, c'est le cas.

Bien sûr, beaucoup de gens ici ont correctement souligné que le contenu de sharedData peuvent encore être modifiés.

Dans ce cas, seul objet shareddata est immmutable, cela signifie seulement que tout le temps, vous travaillerez avec un même objet. Mais toutes les données à l'intérieur, il peut être modifié (enlevé, ajouté, etc.) à tout moment, de tout fil.

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