Bloque sincronizado: son variables "dentro" de otras variables actualizadas

Lo siento por el título no técnico, pero creo que resume bien mi pregunta. Si interpreto lo que he leído correctamente, el bloqueo sincronizado (aparte de otras consecuencias) hará que todas las variables sean actualizadas a / desde la memoria principal (incluso aquellas a las que no se accede explícitamente dentro del bloque sincronizado, solo su "padre"?) . Por ejemplo, citando la respuesta de esta pregunta stackoverflow (lo tomé fuera de contexto, volveré a él más adelante):

La barrera de memoria se aplica a todas las referencias de memoria, incluso las no relacionadas.

Necesito confirmación si interpreto esto correctamente. Tengo 2 subprocesos (threadA, threadB). Considere el siguiente código:

public class SomeClass { private final Object mLock = new Object(); private int[] anArray; public void initA() { synchronized(mLock) { ... anArray = new int[...]; operationA(); } } public void operationA() { synchronized(mLock) { // Manipulating the ELEMENTS of anArray, // eg in loops, etc. anArray[i] = ... } } public int[] getterB() { synchronized(mLock) { return anArray; } } } 

getterB() se llama desde ThreadB , initA() y operationA() se llaman desde ThreadA . (Tenga en cuenta que initA() se llama incluso antes de ThreadB se crea, por lo que sólo getterB() y operationA() son concurrentes.) También tenga en cuenta que tengo una buena razón para no devolver una copia de la matriz en getterB() , ThreadB no quiere cambiar sus elementos, la razón es un requisito externo para mi software que no es relevante ahora).

ThreadB hace lo siguiente:

 int[] anArray = aSomeClass.getterB(); // aSomeClass is an instance of SomeClass if (anArray[i] == n) { ....... } // various operations ... // various other operations that read the elements of anArray 

Como se puede ver, en getterB() , sólo se accede a la referencia anArray dentro de las barreras de memoria, y no a los valores del array en sí. Mis preguntas:

  1. ¿ Se verá el threadB los valores del elemento de la matriz más actualizados? (Es decir, son los propios elementos actualizados también de la memoria principal en getterB() ?)

  2. La declaración citada mencionó que las copias en caché no relacionadas se actualizan desde la memoria principal también. No soy 100% cómo interpretar esto sin relación (no relacionado con la variable utilizada para bloquear? O no relacionado con el bloque sincronizado entero?). Sé que tomé la cotización fuera de contexto, y puesto que es una pregunta diferente del stackoverflow, he agregado un comentario allí . Así que aprecio si esa pregunta mía es contestada allí (o aquí – no me importa).

  3. ¿Hay alguna diferencia en la respuesta si anArray es una matriz de objetos (y no de tipos primitivos)? Ir aún más lejos, ¿qué pasa si no es una matriz, sino una clase que contiene referencias a otras clases? (Es decir, un objeto que se refiere a otros objetos, y acceder a los objetos contenidos a través del objeto devuelto por getterB() ). ¿ Utilizará KB las copias actualizadas de estas referencias contenidas , o puede utilizar sus propias copias locales en caché (puesto que getterB() sólo actualizó su objeto de contenedor, pero no las propias referencias contenidas) ?.

Tomando sus preguntas en orden:

  1. Sí: Se puede asumir con seguridad que todos los valores modificados desde cualquier operationA() previamente llamada operationA() serán "up-to-date" en la matriz referenciada por el resultado de getterB() .

  2. Dejaré que se responda en el otro enlace; Confieso que todavía no leí ese enlace. Pero mi comprensión es que todos los write-backs pendientes de la memoria ocurrirán "con eficacia" mientras que ambos entran y salen de un bloque sincronizado (aunque los detalles de cómo éste sucede – es decir, la eficacia de esto, y si hay más cache / pipelining "Trucos" pasando a hacer que aparezca de esa manera – dependerá del hardware y compilador). Si desea más detalles sobre esto, una vez encontré este enlace útil: http://www.infoq.com/articles/memory_barriers_jvm_concurrency

  3. No, no hay diferencia (dado lo que escribí en la respuesta 2).

Por último, sólo un comentario que sería muy cauteloso de su código como se resume más arriba debido al hecho de que getterB() no devuelve una copia de la matriz. Entiendo que usted tiene sus razones para hacerlo de la manera anterior (y que no quería este tipo de comentarios!), Pero usted debe estar seguro de entender que todas las "diversas operaciones" en el hilo B en anArray que Ocurren después de que getterB() haya devuelto no estará protegido. (En otras palabras, habrá riesgos con cualquier cambio en el arreglo realizado en el hilo A durante este tiempo). Una alternativa que evitaría una copia ineficaz de array profundo es mover estas "diversas operaciones" dentro de un bloque sincronizado dentro de un nuevo método En SomeClass y deshacerse completamente de getterB() . Por supuesto, me doy cuenta de que la "solución correcta" en su código depende de muchas cosas que no se muestran aquí, así que no dude en ignorar este bit.

  • Manejo de errores de actualización
  • Com.android.ant.SetupTask no se puede encontrar
  • Cómo convertir una hora de GMT a EST
  • Intenta invocar el método virtual 'void android.widget.Button.setOnClickListener (android.view.View $ OnClickListener)' en una referencia de objeto nulo
  • ¿Es la mejor práctica para almacenar y usar un token OAuth2 en Android?
  • Actividad se ha filtrado ventana com.android.internal.policy.impl.PhoneWindow$DecorView@46029dd0
  • Array / Lista enlazada: ¿el rendimiento depende de la * dirección * del recorrido?
  • ¿Cómo @Proveer una actividad para el MortarActivityScope, sin filtrar la Actividad en los cambios de orientación?
  • ¿Cómo iniciar una actividad desde una clase java?
  • Http get exception El host de destino no debe ser null en ICS
  • Instalar jar con dependencias para el repositorio maven (Android gcm-server push library)
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.