Pregunta

He leído todo un poco, pero no han encontrado una respuesta definitiva.

Tengo una clase que tiene este aspecto:

    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()) {
                ...
            }
        }
     }

Y me pregunto si es seguro para subprocesos para acceder Datos_compartidos de las instancias de Foo (como se muestra en el constructor y en doSomethingUseful ()). Muchos casos de Foo serán creados en un entorno multi-hilo.

Mi intención es que Datos_compartidos se inicializa en el inicializador estático y no se modificó a partir de entonces (sólo lectura).

Lo que he leído es que los objetos inmutables son inherentemente seguro para subprocesos. Pero sólo he visto esto en lo que parece ser el contexto de las variables de instancia. Son variables estáticas e inmutables hilo de seguridad?

El otro constructo que encontré fue un ConcurrentHashMap. Podría hacer Datos_compartidos de tipo ConcurrentHashMap pero no los HashMaps que contiene también tienen que ser de tipo ConcurrentHashMap? Básicamente ..

private static final ConcurrentHashMap<String, HashMap> sharedData;

o

private static final ConcurrentHashMap<String, ConcurrentHashMap> sharedData;

O sería más seguro (aún más costoso, simplemente clone ())?

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

TIA.

(inicializador estático ha sido editado para dar más contexto.)

¿Fue útil?

Solución

la referencia a sharedData que es final es hilo de seguridad ya que nunca se puede cambiar. El contenido del mapa es no hilo de seguro, ya que necesita ser bien envuelto con preferencia una aplicación ImmutableMap guayaba o java.util.Collections.unmodifiableMap() o utilizar una de las implementaciones del mapa en el paquete java.util.concurrent.

Sólo si lo hace AMBOS va a tener la seguridad de rosca completa en el mapa. Cualquier mapa contenidos tienen que ser inmutable o una de las implementaciones concurrentes también.

.clone () se divide fundamentalmente, se mantenga alejado

clonación por defecto es un clon sin profundidad, se acaba de regresar referencias a objetos contenedores no copias completas. Está bien documentado en la información generalmente disponible sobre por qué.

Otros consejos

Inicialización de campos static final en un bloque de inicialización estática es de subprocesos. Sin embargo, tener en cuenta que el objeto al que unos puntos de referencia estáticos finales pueden no ser seguro para subprocesos. Si el objeto al que se refiere es el hilo de seguridad (por ejemplo, que es inmutable), que está en la clara.

Cada individuo HashMap HashMap contenida en su exterior no está garantizado para ser seguro para subprocesos a menos que utilice ConcurrentHashMap como se sugiere en su pregunta. Si no utiliza una aplicación HashMap interno flujos seguros, puede obtener resultados no deseados cuando dos subprocesos tienen acceso a la misma HashMap interior. Tenga en cuenta que sólo algunas operaciones en ConcurrentHashMap están sincronizados. Por ejemplo, la iteración no es seguro para subprocesos.

Lo que es seguro para subprocesos? Claro, la inicialización del HashMap es seguro para subprocesos en el sentido de que la participación de todos los Foo la misma instancia del mapa, y que el mapa está garantizado para estar allí a menos que ocurra una excepción en el init estática.

Sin embargo, la modificación de los contenidos del mapa es con toda seguridad no seguro para subprocesos. static final significa que el mapa Datos_compartidos no se puede cambiar por otro mapa. Pero el contenido de la correspondencia es una cuestión diferente. Si una clave determinada se utiliza más de una vez al mismo tiempo, es posible obtener los problemas de concurrencia.

No. Excepto si son inmutables.

Lo único que hacen es

  • Sea nivel de clase accesible
  • Evitar la referencia que ser cambiado.

Aún si su atributo es mutable, entonces no es hilo de seguridad.

Vea también: do sincronizamos instancias de variables que son definitivas?

Es exactamente el mismo, salvo que estén al nivel de clase.

Sí, esto es seguro para subprocesos también. Todos los miembros finales de su clase estática serán inicializadas antes de permitir que cualquier hilo para acceder a ellos.

Si el bloque static falla durante la inicialización, un ExceptionInInitializerError será levantado en el hilo que primeros intentos de inicialización. intento posterior para hacer referencia a la clase va a levantar una NoClassDefFoundError.

En general, el contenido de un HashMap no tienen ninguna garantía de visibilidad a través de los hilos. Sin embargo, el código de inicialización clase utiliza un bloque synchronized para evitar que múltiples hilos de la inicialización de la clase. Esta sincronización se enjuagar el estado del mapa (y las instancias HashMap que contiene) para que puedan ser correctamente visible a todas las roscas, suponiendo que no se realizan cambios al mapa, o los mapas que contiene, fuera del inicializador clase.

Vea la de Java Language Specification, § 12.4.2 para obtener información sobre la inicialización de clase y el requisito para la sincronización.

No hay nada inherentemente hilo de seguridad sobre una variable final static. La declaración de una variable miembro final static sólo asegura que esta variable se asigna a una sola vez.

La cuestión de la seguridad de los subprocesos tiene menos que ver con la forma en que declara las variables sino que se basa en la forma de interactuar con las variables. Por lo tanto, no es realmente posible para responder a su pregunta sin más detalles sobre su programa:

  • múltiples hilos de modificar el estado de la variable de sharedData?
  • Si es así, se puede sincronizar en todas las escrituras ( y Lecturas) de sharedData?

Uso de un ConcurrentHashMap sólo garantiza que los métodos individuales de la Map son thread-safe, que no tiene una operación como esta thread-safe:

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

¿No son en realidad se está preguntando si la inicialización estática de sharedData es seguro para subprocesos y sólo ejecuta una vez?

Y sí, ese es el caso.

Por supuesto, muchas personas aquí han señalado correctamente que el contenido de sharedData todavía pueden ser modificados.

En este caso único objeto es Datos_compartidos immmutable, que sólo significa que todo el tiempo que va a trabajar con un mismo objeto. Pero los datos en su interior se pueden cambiar (eliminado, añadido, etc) en cualquier momento, desde cualquier hilo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top