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

votos
4

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 mira cómo el ImmutableListse construye por su constructor - El Builderguarda todos los elementos en un Object[](eso está bien ya que 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 de lectura:

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

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

    ...
}

¿Cómo se puede hilo de seguridad? Lo que garantiza el que ocurre antes relación entre las escrituras realizadas 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 desbloquear suceda 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 de una unión de 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í?

Publicado el 07/11/2018 a las 22:29
fuente por usuario
En otros idiomas...                            


3 respuestas

votos
2

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;
    }
}

La semántica de campo finales garantiza que los lectores verán una serie de puesta al día:

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 con el 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 .

Respondida el 07/11/2018 a las 22:48
fuente por usuario

votos
1

Como ha afirmado: " 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. "

Obviamente, si un hilo de alguna manera tiene acceso al objeto antes de que el constructor se invoca incluso, estaría jodido. Así que algo debe evitar que el objeto que se tiene acceso antes de que sus retornos constructor. Pero una vez que el constructor devoluciones, lo que le permite otro acceso hilo del objeto es seguro, ya que sucede después en el orden del programa de construcción de la rosca.

hilo de seguridad básica con cualquier objeto compartido se logra asegurando que todo lo que permite a los hilos para acceder al objeto no tiene lugar hasta que las declaraciones del constructor, que establece que cualquier cosa que el constructor podría hacer que sucede antes de que cualquier otro hilo podría acceder al objeto.

El flujo es:

  1. El objeto no existe y no se puede acceder.
  2. Algunos subproceso llama el constructor del objeto (o hace lo que sea necesario para obtener el objeto listo para ser utilizado).
  3. Ese hilo hace algo para permitir que otros hilos para acceder al objeto.
  4. Otros temas pueden ahora acceder al objeto.

fin del programa de la rosca invocando el constructor garantiza que ninguna parte de 4 ocurre hasta que todos los 2 está hecho.

Tenga en cuenta que esto se aplica de la misma manera si las cosas se deben hacer después de que los rendimientos del constructor, que sólo les puede considerar lógicamente parte del proceso de construcción. Y del mismo modo, partes del trabajo se puede hacer por otros hilos tanto tiempo como todo lo que tiene que ver el trabajo realizado por otro hilo no puede comenzar hasta que se establezca algún tipo de relación con el trabajo que hizo otro hilo.

¿Eso no es 100% responde a su pregunta?

Para reiterar:

¿Cómo se puede hilo de seguridad? Lo que garantiza la relación sucede-antes entre las escrituras realizadas en el generador y las lecturas de RegularImmutableList?

La respuesta es lo que impidió el objeto de ser visitada antes de que el constructor fue incluso llamada (que tiene que ser algo, de lo contrario estaríamos completamente atornillado) sigue impidiendo el objeto de ser visitada hasta después de las declaraciones de constructor. El constructor es efectivamente una operación atómica porque ningún otro hilo podría intentar acceder al objeto mientras se está ejecutando. Una vez que el constructor devoluciones, cualquiera que sea el hilo que llama al constructor hace para permitir que otros hilos para acceder al objeto tiene lugar necesariamente después de que los rendimientos de constructor porque, "[e] acción ada en un hilo sucede-antes de cada acción en ese hilo que viene después el fin del programa ".

Y, una vez más:

Si algún hilo construye la lista y pasa su referencia a algunos otros hilos sin el uso de bloqueos (por ejemplo a través de un campo final o volátil), no veo lo que garantiza de hilo de seguridad. ¿Qué me estoy perdiendo?

El hilo se acumula primero la lista y luego siguiente pasa su referencia. El edificio de la lista de "pasa-antes de cada acción en ese hilo que viene más adelante con el fin de programa" y así sucede, antes de la aprobación de la referencia. Así, cualquier hilo que ve el paso de la referencia pasa-después de la construcción de la lista de completado.

Si este no es el caso, no habría ninguna buena manera de construir un objeto en un hilo y luego dar otros hilos acceso a ella. Pero esto es perfectamente seguro hacerlo porque el método que se utiliza para entregar el objeto a partir de un hilo a otro va a establecer la relación necesariamente.

Respondida el 08/11/2018 a las 00:01
fuente por usuario

votos
0

Usted está hablando de dos cosas diferentes aquí.

  1. El acceso ya que construyó RegularImmutableListy su arrayes seguro para subprocesos, ya que no habrá ningún escrituras concurrentes y lee a la matriz. Sólo lecturas simultáneas.

  2. La cuestión enhebrar puede suceder cuando se pasa a otro hilo. Pero eso no tiene nada que ver con RegularImmutableListpero con qué otros temas, véase la referencia a la misma. Digamos crea un hilo RegularImmutableListy pasa su referencia a otro hilo. Por el otro hilo a ver que la referencia se ha actualizado y ahora está apuntando a la nueva creada RegularImmutableListtendrá que utilizar cualquiera synchronizationo volatile.

EDITAR:

Creo que la preocupación OP tiene es como JMM se asegura de que todo lo que llegó a escribirse en el arraydespués de su creación a partir de un hilo edificio recibe visible para otros hilos después de su referencia se pasa a ellos.

Esto ocurre por el uso o volatileo synchronization. Cuando, por ejemplo hilo lector asigna RegularImmutableLista la variable volátil del JMM se asegurará de que todas las escrituras en serie consiguen destellaron en la memoria principal y cuando otro hilo lee de ella JMM se asegura de que va a ver todo brilló escrituras.

Respondida el 07/11/2018 a las 22:44
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more