Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /
CRUD

Threading - Java SDK

To make your Android apps fast and responsive, you must balance the computing time needed to lay out the visuals and handle user interactions with the time needed to process your data and run your business logic. Typically, app developers spread this work across multiple threads: the main or UI thread for all of the user interface-related work, and one or more background threads to compute heavier workloads before sending it to the UI thread for presentation. By offloading heavy work to background threads, the UI thread can remain highly responsive regardless of the size of the workload.

Realm enables simple and safe multithreaded code when you follow these three rules:

Avoid writes on the UI thread if you write on a background thread:
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.
Don't pass live objects, collections, or realms to other threads:
Live objects, collections, and realm instances are thread-confined: that is, they are only valid on the thread on which they were created. Practically speaking, this means you cannot pass live instances to other threads. However, Realm offers several mechanisms for sharing objects across threads.
No bloquees 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.

When you need to communicate across threads, you have several options depending on your use case:

  • To modify the data on two threads, query for the object on both threads using a primary key.

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

  • To keep and share many read-only views of the object in your app, copy the object from the realm.

  • To react to changes made on any thread, use notifications.

  • 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).

Managed 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.

Live, thread-confined objects work fine in most cases. However, some apps -- those based on reactive, event stream-based architectures, for example -- need to send immutable copies across threads. In this case, you can freeze objects, collections, and realms.

Freezing creates an immutable view of a specific object, collection, or realm that still exists on disk and does not need to be deeply copied when passed around to other threads. You can freely share a frozen object across threads without concern for thread issues.

Frozen objects are not live and do not automatically update. They are effectively snapshots of the object state at the time of freezing. When you freeze a realm all child objects and collections also become frozen. You can't modify frozen objects, but you can read the primary key from a frozen object, query a live realm for the underlying object, and then update that live object instance.

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

Frozen Object Exceptions

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

  • Opening a write transaction on a frozen realm.

  • Modifying a frozen object.

  • Adding a change listener to a frozen realm, collection, or object.

Once frozen, you cannot unfreeze an object. You can use isFrozen() to check if an object is frozen. This method is always thread-safe.

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

Frozen Objects and Realm Size

Frozen objects preserve an entire copy of the realm that contains them at the moment they were frozen. As a result, freezing a large number of objects can cause a realm to consume more memory and storage than it might have without frozen objects. If you need to separately freeze a large number of objects for long periods of time, consider copying what you need out of the realm instead.

When you open a realm, it reflects the most recent successful write commit and remains on that version until it is refreshed. This means that the realm will not see changes that happened on another thread until the next refresh. Realms on any event loop thread (including the UI thread) automatically refresh themselves at the beginning of that thread's loop. However, you must manually refresh realm instances that are tied to non-looping threads or that have auto-refresh disabled. To refresh a realm, call Realm.refresh():

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

Tip

Refresh on Write

Realms also automatically refresh after completing a write transaction.

Realm proporciona acceso seguro, rápido, sin bloqueos y concurrente entre hilos con su Control de concurrencia multiversión (MVCC) arquitectura.

If you are familiar with a distributed version control system like Git, you may already have an intuitive understanding of MVCC. Two fundamental elements of Git are:

  • Commits, which are atomic writes.

  • Branches, which are different versions of the commit history.

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 favorece activamente la distribución y la divergencia mediante bifurcación (forking), un realm solo tiene una última versión verdadera en un momento dado y siempre escribe en la cabeza de esa última versión. Realm no puede guardar en una versión anterior. Esto tiene sentido; los datos deben converger en la última versión de la verdad.

A realm is implemented using a B+ tree data structure. The top-level node represents a version of the realm; child nodes are objects in that version of the realm. The realm has a pointer to its latest version, much like how Git has a pointer to its HEAD commit.

Realm uses a copy-on-write technique to ensure isolation and durability. When you make changes, Realm copies the relevant part of the tree for writing, then commits the changes in two phases:

  • Write changes to disk and verify success.

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

This two-step commit process guarantees that even if the write failed partway, the original version is not corrupted in any way because the changes were made to a copy of the relevant part of the tree. Likewise, the realm's root pointer will point to the original version until the new version is guaranteed to be valid.

Ejemplo

The following diagram illustrates the commit process:

Realm copia la parte relevante del árbol para los guardados y luego reemplaza la última versión actualizando un puntero.
haga clic para ampliar
  1. The realm is structured as a tree. The realm has a pointer to its latest version, 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 datos. Cuando lees un valor del realm, en realidad estás viendo el valor en el disco físico, no una copia de él. Esta es la base de objetos activos. Esta es también la razón por la que un puntero principal de realm puede configurarse para apuntar a la nueva versión después de que la escritura en disco haya sido validada.

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

    • Avoid writes on the UI thread if you write on background threads or use Sync.

    • Don't pass live objects to other threads.

    • No bloquees para leer.

  • In order to see changes made on other threads in your realm instance, you must manually refresh realm instances that do not exist on "loop" threads or that have auto-refresh disabled.

  • 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