Lo que garantiza la seguridad de los subprocesos de ImmutableList de guayaba?

malta:

El Javadoc en Guava ImmutableList dice que la clase tiene las propiedades de Guava ImmutableCollection , uno de los cuales es la seguridad de rosca:

Seguridad de los hilos. Es seguro para acceder a esta colección simultáneamente desde varios subprocesos.

Pero vistazo a cómo la ImmutableListestá construido por su constructor - El Builderguarda todos los elementos en un Object[](Eso es bueno, ya nadie dijo que el constructor era seguro para hilos) y sobre la construcción pasa a esa matriz (o, posiblemente, una copia) al constructor de RegularImmutableList :

public abstract class ImmutableList<E> extends ImmutableCollection<E>
implements List<E>, RandomAccess {
    ...
    static <E> ImmutableList<E> asImmutableList(Object[] elements, int length) {
      switch (length) {
        case 0:
          return of();
        case 1:
          return of((E) elements[0]);
        default:
          if (length < elements.length) {
            elements = Arrays.copyOf(elements, length);
          }
          return new RegularImmutableList<E>(elements);
      }
    }
    ...
    public static final class Builder<E> extends ImmutableCollection.Builder<E> {
        Object[] contents;
        ...
        public ImmutableList<E> build() { //Builder's build() method
          forceCopy = true;
          return asImmutableList(contents, size);
        }
        ...
    }

}

¿Qué RegularImmutableListhacer con estos elementos? Lo que se espera, simplemente inicia su matriz interna, que luego se utiliza para todas las elaboraciones leer:

class RegularImmutableList<E> extends ImmutableList<E> {
    final transient Object[] array;

    RegularImmutableList(Object[] array) {
      this.array = array;
    }

    ...
}

¿Cómo es esta caja fuerte del hilo sea? Lo que garantiza la sucede, antes de relación entre las escrituras a cabo en el Buildery la lee desde RegularImmutableList?

De acuerdo con el modelo de memoria de Java hay una relación sucede-antes sólo en cinco casos (desde el Javadoc para java.util.concurrent):

  • Cada acción en un hilo sucede-antes de cada acción en ese hilo que viene más adelante con el fin del programa.
  • Una de desbloqueo (bloque o método sincronizado salida) de un monitor de pasa-antes de cada bloqueo posterior de ese mismo monitor (bloque o entrada método sincronizado). Y debido a que la sucede, antes de relación es transitiva, todas las acciones de un hilo antes de desbloqueo ocurren antes todas las acciones posteriores a cualquier hilo de bloqueo ese monitor.
  • Una escritura en un campo volátil sucede-antes de cada lectura posterior de ese mismo campo. Escribe y lee de campos volátiles tienen efectos de coherencia de memoria similares a entrar y salir de monitores, pero no implican la exclusión mutua de bloqueo.
  • Una llamada a comenzar en un hilo sucede-antes de cualquier acción en el hilo comenzado.
  • Todas las acciones en un hilo suceden-antes de que cualquier otro hilo regresa con éxito a partir de una combinación en ese hilo.

Ninguno de ellos parece aplicarse aquí. Si algún hilo construye la lista y pasa su referencia a algunos otros hilos sin utilizar cerraduras (por ejemplo a través de una finalo volatilecampo), no veo lo que garantiza de hilo de seguridad. ¿Qué me estoy perdiendo?

Editar:

Sí, la escritura de la referencia a la matriz es seguro para subprocesos en razón de que sea final. De manera que es hilo claramente segura. Lo que me pregunto acerca eran las escrituras de los elementos individuales. Los elementos de la matriz son ni finalni volatile. Sin embargo, ellos parecen estar escrito por un hilo y leído por otro sin sincronización.

Así que la pregunta se puede reducir a "si el subproceso A escribe en un finalcampo, hace que la garantía de que otros hilos verán que no sólo escribir, sino todas las escrituras anteriores de A así?"

Oleksandr Pyrohov:

JMM garantiza la inicialización de seguridad (todos los valores inicializados en el constructor serán visibles para los lectores) si todos los campos del objeto son finaly no hay fugas de thisdesde el constructor 1 :

class RegularImmutableList<E> extends ImmutableList<E> {

    final transient Object[] array;
      ^

    RegularImmutableList(Object[] array) {
        this.array = array;
    }
}

El campo final semántica garantiza que los lectores verán una serie hasta a la fecha:

Los efectos de todas las inicializaciones deben estar comprometidos con la memoria antes de cualquier código constructor después publica la referencia al objeto de nueva construcción.


Gracias a @JBNizet y para @chrylis para el enlace a los JLS.

1 - "Si esto es seguido, a continuación, cuando el objeto es visto por otro hilo, que el hilo siempre ver la versión correctamente construida de campos finales de ese objeto. También ver versiones de cualquier objeto o matriz referenciado por aquellos campos finales que son al menos como hasta a la fecha que los campos son finales ". - JLS §17.5 .

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=189612&siteId=1
Recomendado
Clasificación