Docs Menu
Docs Home
/ /
CRUD

Subprocesos - SDK de Java

Para que tus aplicaciones Android sean rápidas y responsivas, debes equilibrar el tiempo de procesamiento necesario para diseñar las imágenes y gestionar las interacciones del usuario con el tiempo necesario para procesar los datos y ejecutar la lógica de negocio. Normalmente, los desarrolladores de aplicaciones distribuyen este trabajo entre varios hilos: el hilo principal o de interfaz de usuario para todo el trabajo relacionado con la interfaz de usuario, y uno o más hilos en segundo plano para procesar las cargas de trabajo más pesadas antes de enviarlas al hilo de interfaz de usuario para su presentación. Al transferir el trabajo pesado a los hilos en segundo plano, el hilo de interfaz de usuario puede mantener una alta capacidad de respuesta independientemente del tamaño de la carga de trabajo.

Realm permite un código multiproceso simple y seguro cuando sigues estas tres reglas:

Evite escrituras en el hilo de UI si escribe en un hilo en segundo plano:
Puedes escribir en un dominio desde cualquier hilo, pero solo puede haber un escritor a la vez. Por lo tanto, las transacciones de escritura se bloquean entre sí. Una escritura en el hilo de la interfaz de usuario puede provocar que tu aplicación parezca no responder mientras espera a que se complete una escritura en un hilo en segundo plano. Si estás usando Sincronización: evita escribir en el hilo de UI, ya que Sync escribe en un hilo en segundo plano.
No pase objetos activos, colecciones o reinos a otros subprocesos:
Los objetos activos, las colecciones y las instancias de realm están confinados a subprocesos: es decir, solo son válidos en el subproceso en el que se crearon. En la práctica, esto significa que no se pueden pasar instancias activas a otros subprocesos. Sin embargo, Realm ofrece varios mecanismos para compartir objetos entre subprocesos.
No bloquear para leer:
La arquitectura de Control de Concurrencia Multiversión (MVCC) de Realm elimina la necesidad de bloqueos para las operaciones de lectura. Los valores leídos nunca se corromperán ni se modificarán parcialmente. Se puede leer libremente desde los dominios en cualquier hilo sin necesidad de bloqueos ni mutex. Un bloqueo innecesario supondría un cuello de botella en el rendimiento, ya que cada hilo podría tener que esperar su turno antes de leer.

Los objetos, colecciones y dominios activos están confinados a subprocesos. Si necesita trabajar con los mismos datos en varios subprocesos, debe abrir el mismo dominio en varios subprocesos como instancias independientes. El SDK de Java consolida las conexiones subyacentes entre subprocesos siempre que sea posible para que este patrón sea más eficiente.

Cuando necesita comunicarse a través de subprocesos, tiene varias opciones según su caso de uso:

  • Para modificar los datos en dos subprocesos, consulte el objeto en ambos subprocesos utilizando una clave principal.

  • Para enviar una vista rápida y de solo lectura de un objeto a otros subprocesos, congele el objeto.

  • Para conservar y compartir muchas vistas de solo lectura del objeto en su aplicación, copie el objeto desde el reino.

  • Para reaccionar a los cambios realizados en cualquier hilo, utiliza notificaciones.

  • Para ver los cambios de otros hilos del reino en el hilo actual, actualice su instancia del reino (los hilos del bucle de eventos se actualizan automáticamente).

Administrado RealmObject Las instancias no son seguras Parcelable para subprocesos ni, por lo que no se pueden pasar entre actividades o subprocesos mediante Intent un. En su lugar, se puede pasar un identificador de objeto, como una clave principal, en el Intent paquete de extras y luego abrir una nueva instancia de realm en el subproceso independiente para consultar dicho identificador. Como alternativa, se pueden inmovilizar objetos de realm.

Tip

Puede encontrar ejemplos prácticos en Pasar objetosParte del ejemplo de subprocesos del SDK de Java. El ejemplo muestra cómo pasar identificadores y recuperar un RealmObject en casos de uso comunes de Android.

Los objetos activos y confinados en subprocesos funcionan correctamente en la mayoría de los casos. Sin embargo, algunas aplicaciones (por ejemplo, las basadas en arquitecturas reactivas basadas en flujos de eventos) necesitan enviar copias inmutables entre subprocesos. En este caso, se pueden congelar objetos, colecciones y dominios.

La congelación crea una vista inmutable de un objeto, colección o reino específico que aún existe en el disco y no necesita copiarse en profundidad al pasarse a otros subprocesos. Puedes compartir libremente un objeto congelado entre subprocesos sin preocuparte por problemas.

Los objetos congelados no están activos y no se actualizan automáticamente. Son, en realidad, instantáneas del estado del objeto en el momento de la congelación. Al congelar un reino, todos los objetos secundarios y colecciones también se congelan. No se pueden modificar los objetos congelados, pero se puede leer la clave principal de un objeto congelado, consultar un reino activo para el objeto subyacente y, a continuación, actualizar esa instancia del objeto activo.

Los objetos congelados siguen siendo válidos mientras el reino que los generó permanezca abierto. Evite cerrar reinos que contengan objetos congelados hasta que todos los subprocesos hayan terminado de trabajar con ellos.

Advertencia

Excepciones de objetos congelados

Al trabajar con objetos congelados, cualquier intento de realizar cualquiera de las siguientes acciones genera una excepción:

  • Abriendo una transacción de escritura en un reino congelado.

  • Modificar un objeto congelado.

  • Agregar un detector de cambios a un reino, una colección o un objeto congelado.

Una vez congelado, no se puede descongelar un objeto. Se puede usar isFrozen() para comprobar si un objeto está congelado. Este método siempre es seguro para subprocesos.

Para congelar un objeto, una colección o un reino, utilice el método freeze():

Realm realm = Realm.getInstance(config);
// Get an immutable copy of the realm that can be passed across threads
Realm frozenRealm = realm.freeze();
Assert.assertTrue(frozenRealm.isFrozen());
RealmResults<Frog> frogs = realm.where(Frog.class).findAll();
// You can freeze collections
RealmResults<Frog> frozenFrogs = frogs.freeze();
Assert.assertTrue(frozenFrogs.isFrozen());
// You can still read from frozen realms
RealmResults<Frog> frozenFrogs2 = frozenRealm.where(Frog.class).findAll();
Assert.assertTrue(frozenFrogs2.isFrozen());
Frog frog = frogs.first();
Assert.assertTrue(!frog.getRealm().isFrozen());
// You can freeze objects
Frog frozenFrog = frog.freeze();
Assert.assertTrue(frozenFrog.isFrozen());
// Frozen objects have a reference to a frozen realm
Assert.assertTrue(frozenFrog.getRealm().isFrozen());
val realm = Realm.getInstance(config)
// Get an immutable copy of the realm that can be passed across threads
val frozenRealm = realm.freeze()
Assert.assertTrue(frozenRealm.isFrozen)
val frogs = realm.where(Frog::class.java).findAll()
// You can freeze collections
val frozenFrogs = frogs.freeze()
Assert.assertTrue(frozenFrogs.isFrozen)
// You can still read from frozen realms
val frozenFrogs2 =
frozenRealm.where(Frog::class.java).findAll()
Assert.assertTrue(frozenFrogs2.isFrozen)
val frog: Frog = frogs.first()!!
Assert.assertTrue(!frog.realm.isFrozen)
// You can freeze objects
val frozenFrog: Frog = frog.freeze()
Assert.assertTrue(frozenFrog.isFrozen)
Assert.assertTrue(frozenFrog.realm.isFrozen)

Importante

Objetos congelados y tamaño del reino

Los objetos congelados conservan una copia completa del reino que los contenía en el momento de su congelación. Por lo tanto, congelar una gran cantidad de objetos puede provocar que un reino consuma más memoria y almacenamiento que sin ellos. Si necesita congelar una gran cantidad de objetos por separado durante largos periodos, considere copiar lo que necesite fuera del reino.

Al abrir un reino, este refleja la última confirmación de escritura correcta y permanece en esa versión hasta que se actualiza. Esto significa que el reino no verá los cambios realizados en otro hilo hasta la siguiente actualización. Los reinos de cualquier hilo de bucle de eventos (incluido el hilo de interfaz de usuario) se actualizan automáticamente al inicio del bucle de ese hilo. Sin embargo, debe actualizar manualmente las instancias de reino asociadas a hilos que no participan en bucles o que tienen la actualización automática deshabilitada. Para actualizar un reino, llame a Realm.refresh():

if (!realm.isAutoRefresh()) {
// manually refresh
realm.refresh();
}
if (!realm.isAutoRefresh) {
// manually refresh
realm.refresh()
}

Tip

Actualizar al escribir

Los reinos también se actualizan automáticamente después de completar una transacción de escritura.

Realm proporciona acceso seguro, rápido, sin bloqueos y simultáneo entre subprocesos con su arquitectura de control de concurrencia multiversión (MVCC).

Si está familiarizado con un sistema de control de versiones distribuido como Git, es posible que ya tenga una comprensión intuitiva de MVCC. Dos elementos fundamentales de Git son:

  • Confirmaciones, que son escrituras atómicas.

  • Ramas, que son diferentes versiones del historial de confirmaciones.

De forma similar, Realm cuenta con escrituras confirmadas atómicamente en forma de transacciones. Realm también cuenta con múltiples versiones del historial en un momento dado, como las ramas.

A diferencia de Git, que apoya activamente la distribución y la divergencia mediante bifurcaciones, un reino solo tiene una versión más reciente en un momento dado y siempre escribe en la cabecera de esa última versión. Un reino no puede escribir en una versión anterior. Esto tiene sentido: tus datos deberían converger en una versión más reciente de la verdad.

Un reino se implementa mediante una estructura de datos de árbol B+. El nodo de nivel superior representa una versión del reino; los nodos secundarios son objetos de esa versión. El reino tiene un puntero a su última versión, similar a cómo Git tiene un puntero a su confirmación HEAD.

Realm utiliza una técnica de copia en escritura para garantizar el aislamiento y la durabilidad. Al realizar cambios, Realm copia la parte relevante del árbol para su escritura y luego confirma los cambios en dos fases:

  • Escriba los cambios en el disco y verifique el éxito.

  • Establezca el puntero de la última versión para que apunte a la versión recién escrita.

Este proceso de confirmación en dos pasos garantiza que, incluso si la escritura falla a mitad de camino, la versión original no se corrompa, ya que los cambios se realizaron en una copia de la parte relevante del árbol. Asimismo, el puntero raíz del dominio apuntará a la versión original hasta que se garantice la validez de la nueva versión.

Ejemplo

El siguiente diagrama ilustra el proceso de confirmación:

Realm copia la parte relevante del árbol para las escrituras y luego reemplaza la última versión actualizando un puntero.
haga clic para ampliar
  1. El dominio está estructurado como un árbol. Tiene un puntero a su última versión, V1.

  2. Cuando se realiza una escritura, Realm crea una nueva versión V2 basada en V1. Realm crea copias de objetos para su modificación (A 1, C 1), mientras que los enlaces a objetos no modificados siguen apuntando a las versiones originales (B, D).

  3. Después de validar la confirmación, Realm actualiza el puntero a la nueva versión más reciente, V2. A continuación, Realm descarta los nodos antiguos que ya no están conectados al árbol.

Realm utiliza técnicas de copia cero, como el mapeo de memoria, para gestionar los datos. Al leer un valor del realm, prácticamente se ve el valor en el disco real, no una copia. Esta es la base de los objetos activos. Por eso también se puede configurar un puntero principal del realm para que apunte a la nueva versión tras validar la escritura en el disco.

  • Realm permite un código multiproceso simple y seguro cuando se siguen tres reglas:

    • Evite escribir en el hilo de UI si escribe en hilos en segundo plano o usa Sync.

    • No pase objetos vivos a otros subprocesos.

    • No bloquear para leer.

  • Para ver los cambios realizados en otros subprocesos de su instancia de reino, debe actualizar manualmente las instancias de reino que no existen en subprocesos de "bucle" o que tienen la actualización automática deshabilitada.

  • Para las aplicaciones basadas en arquitecturas reactivas basadas en flujo de eventos, puede congelar objetos, colecciones y reinos para pasar copias de manera eficiente a diferentes subprocesos para su procesamiento.

  • La arquitectura de control de concurrencia multiversión (MVCC) de Realm es similar a la de Git. A diferencia de Git, Realm solo tiene una versión actualizada para cada reino.

  • Realm realiza compromisos en dos etapas para garantizar el aislamiento y la durabilidad.

Volver

Filtro de datos

En esta página