threads - Java: cómo sincronizar los accesos a la matriz y cuáles son las limitaciones de lo que entra en una condición sincronizada
synchronized class in java (4)
Cuando sincroniza un Objeto o matriz, impide que otro subproceso se sincronice con el mismo objeto. Esto no le impide usar el objeto y ninguna otra operación está "bloqueada". Debe asegurarse de que bloqueó el objeto primero de manera consistente para "bloquear" el objeto.
Tenía una matriz de 2x2 en la que tenía dos hilos operando.
es posible usar una instrucción sincronizada en Java en una matriz?
¿Cómo funciona el bloqueo? el hilo del tutorial de Java decía que la declaración sincronizada funciona en los objetos, por lo que no estaba seguro de lo que significaban. Otro sitio dijo que podía hacer una declaración como
synchronized (array1[]){
}
¿Esto sincroniza accesos a todo en la matriz para que la matriz esté bloqueada a otros hilos?
si tengo una matriz de dos discos puedo usar
synchronized (array1[i])
para bloquear una de las filas de la matriz?
y es posible bloquear valores de matriz individuales con algo así como
synchronized (array1[i][j]){
}
Pero sí, consejos o ayuda son muy apreciados. En realidad, ya lo entregué, es correcto o no. Pero quiero saber para uso futuro
La palabra clave synchronized
solo funciona con Objetos.
La sincronización en la matriz solo se bloquea en la matriz (en Java una matriz es un objeto).
Si se sincroniza en algún elemento individual de la matriz, suponiendo que son objetos y no primitivos, ese es otro bloqueo diferente. Puedes tener uno sin el otro, y el inverso también es verdad. No puedes sincronizar en un primitivo.
Si necesita evitar la modificación simultánea de la matriz, sincronice en algún objeto en cada acceso a la matriz. Puede usar cualquier objeto que desee para este fin, pero tiene que ser el mismo para que funcione. Tenga en cuenta que si accede a un recurso compartido con sincronización y en otras partes del código al que accede sin sincronizar o sincronizar en otro objeto, entonces eso no sirve para nada.
No, sincronizar de esta manera solo significa que está bloqueando el objeto de la matriz, no que realmente está sincronizando el acceso a sus métodos. Si su matriz es visible para otros, aún puede acceder / modificar su contenido independientemente de si está bloqueado o no. Solo que no pueden bloquearlo al mismo tiempo; si lo intentan (desde un subproceso diferente), se bloquearán hasta que su adquirente original libere el bloqueo.
Si desea asegurarse de que solo un subproceso está accediendo a su matriz (o un elemento de ella) a la vez, debe encapsularla en una clase y sincronizar todos los métodos de clase pública que manipulan la matriz. (Sin embargo, puede bloquear la matriz para este fin, si lo desea, el enfoque más simple y habitual es declarar los métodos en sí mismos como synchronized
, en cuyo caso su contenido está sincronizado en this
, el objeto adjunto).
class ArrayWrapper {
private int[] array = ...;
public void setValue(int index, int value) {
synchronized (array) {
array[index] = value;
}
}
public int getValue(int index) {
synchronized (array) {
return array[index];
}
}
...
}
Sí, puede sincronizar usando una matriz como objeto monitor, porque las matrices (incluso las matrices de primitivas) son objetos en Java.
Puede sincronizar un bloque de código en un monitor específico como este:
public void myMethod() {
unsynchronized_statements...
synchronized(myMonitorObject) {
synchronized_statments...
}
Lo mejor es sincronizar el menor número de líneas de código posible.
La sincronización del código en un monitor no afecta al monitor de ninguna manera, solo afecta a los subprocesos que acceden al bloque de código sincronizado. Antes de que la ejecución del hilo pueda ingresar al bloque de código, debe obtener ''el bloqueo'' en el monitor. El tiempo de ejecución de Java garantiza que, como máximo, un hilo a la vez pueda tener ''el bloqueo'' en un monitor. ¡Así que la sincronización en su matriz no impide que los bloques de código no sincronizados accedan a ella! El truco es asegurarse de que todas las operaciones que no desea que ocurran al mismo tiempo estén dentro de bloques sincronizados en el mismo monitor.
Dado que Java no ofrece matrices multidimensionales, solo matrices de matrices, sin duda puede sincronizar en una matriz anidada para una sincronización más fina. Si modela una matriz 2d como una matriz de filas, solo puede sincronizar en filas, no en columnas porque en ese ejemplo las columnas no se representan como matrices separadas.
Solo puede sincronizar en valores de matriz individuales si estos no son primitivos, por lo que es Integer () en lugar de int. Tenga en cuenta que Integer () es un objeto inmutable, por lo que no podrá cambiar su valor. Una solución sería crear su propio objeto contenedora Cell () con un getter y un setter para el valor numérico contenido. Esto le permitirá dejar que un hilo consiga un bloqueo en la Celda y cambie su valor de forma segura.
Como es mi día libre, decidí divertirme un poco y crear un ejemplo práctico de lo que describes. Sí, esta es mi idea de divertirme.
Clases:
- Matriz : representación de una matriz 2d de celdas
- Celda : envoltorio para un valor de celda matriz
- Operación : una operación abstracta en una matriz de celdas
- IncrementOperation : una operación que incrementa cada valor de celda
- ReverseOperation : una operación que invierte el orden de las celdas
- Principal : la aplicación
La aplicación inicia múltiples operaciones en la misma matriz. El único bloque sincronizado de código está en la clase Operación. Si elimina la sincronización, los resultados serán incorrectos porque dos operaciones están manipulando la misma fila simultáneamente.
Salida cuando está sincronizado:
[105, 104, 103, 102, 101]
[110, 109, 108, 107, 106]
[115, 114, 113, 112, 111]
[120, 119, 118, 117, 116]
[125, 124, 123, 122, 121]
[130, 129, 128, 127, 126]
[135, 134, 133, 132, 131]
[140, 139, 138, 137, 136]
[145, 144, 143, 142, 141]
[150, 149, 148, 147, 146]
Ejemplo de salida cuando NO está sincronizado:
[105, 4, 103, 102, 101]
[110, 9, 108, 207, 106]
[115, 14, 113, 212, 111]
[120, 19, 118, 217, 116]
[125, 124, 123, 122, 121]
[130, 129, 128, 127, 126]
[135, 34, 133, 232, 131]
[140, 139, 138, 137, 136]
[145, 144, 143, 142, 141]
[150, 149, 148, 147, 146]
Tenga en cuenta que agregué algunas instrucciones Thread.sleep () en las implementaciones de operación para hacer la diferencia entre la ejecución sincronizada y no sincronizada más obvia.