Exchanger
Exchanger
Documentación sobre Exchanger en Java
Introducción a Exchanger
Exchanger<T> es una clase de Java perteneciente al paquete java.util.concurrent que proporciona un mecanismo de sincronización entre dos hilos, permitiendo que intercambien objetos de manera segura y eficiente. Este mecanismo es útil cuando se necesita coordinar el procesamiento de datos entre dos subprocesos antes de que continúen con sus respectivas tareas.
Funcionamiento de Exchanger
El Exchanger<T> actúa como un punto de sincronización donde dos hilos pueden llamar al método exchange(T obj), intercambiando los objetos que pasan como parámetro. El intercambio ocurre cuando ambos hilos han invocado el método exchange. Si un hilo llega primero, quedará bloqueado hasta que el otro hilo también invoque el método.
Principales Características
- Intercambio directo: Dos hilos intercambian datos directamente en un punto de sincronización.
- Sincronización obligatoria: Ambos hilos deben llegar al punto de intercambio para que la operación se complete.
- Bidireccionalidad: Cada hilo proporciona un objeto y recibe otro a cambio.
- Bloqueo hasta la sincronización: Si un hilo llega antes, se bloquea hasta que llegue el otro.
- Tiempo de espera opcional: Existe una versión sobrecargada del método
exchangeque permite especificar un tiempo de espera.
Implementación en Java
A continuación, se muestra un ejemplo de implementación de Exchanger en Java, donde dos hilos intercambian datos.
import java.util.concurrent.Exchanger;
class PrimerHilo implements Runnable {
private Exchanger<Integer> exchanger;
public PrimerHilo(Exchanger<Integer> exchanger) {
this.exchanger = exchanger;
}
@Override
public void run() {
try {
int datosParaEnviar = 10;
System.out.println("Primer hilo enviando: " + datosParaEnviar);
int datosRecibidos = exchanger.exchange(datosParaEnviar);
System.out.println("Primer hilo recibió: " + datosRecibidos);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class SegundoHilo implements Runnable {
private Exchanger<Integer> exchanger;
public SegundoHilo(Exchanger<Integer> exchanger) {
this.exchanger = exchanger;
}
@Override
public void run() {
try {
Thread.sleep(3000);
int datosParaEnviar = 20;
System.out.println("Segundo hilo enviando: " + datosParaEnviar);
int datosRecibidos = exchanger.exchange(datosParaEnviar);
System.out.println("Segundo hilo recibió: " + datosRecibidos);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class ExchangerDemo {
public static void main(String[] args) {
Exchanger<Integer> exchanger = new Exchanger<>();
Thread hilo1 = new Thread(new PrimerHilo(exchanger));
Thread hilo2 = new Thread(new SegundoHilo(exchanger));
hilo1.start();
hilo2.start();
}
}
Explicación del Código
- PrimerHilo y SegundoHilo:
- Ambos implementan
Runnabley utilizan unExchanger<Integer>. PrimerHiloenvía el valor10y espera a recibir un valor deSegundoHilo.SegundoHiloduerme durante 3 segundos antes de llamar aexchange(20), lo que simula un retraso en la sincronización.- Una vez que ambos hilos han alcanzado el punto de sincronización, intercambian los datos.
- Ambos implementan
Salida Esperada
Primer hilo enviando: 10
(segundos de espera debido a Thread.sleep en SegundoHilo)
Segundo hilo enviando: 20
Primer hilo recibió: 20
Segundo hilo recibió: 10
Comparación entre Exchanger y Queue
Aunque Exchanger y Queue pueden usarse para la sincronización entre hilos, existen diferencias clave:
| Característica | Exchanger | Queue (Cola) |
|---|---|---|
| Tipo de comunicación | Bidireccional | Unidireccional |
| Sincronización | Ambos hilos deben esperar para intercambiar datos | Puede haber productores y consumidores asíncronos |
| Uso recomendado | Cuando dos hilos necesitan sincronizar e intercambiar datos de manera directa | Cuando hay múltiples productores/consumidores y se necesita almacenamiento temporal de datos |
| Ejemplo de implementación | Exchanger<T> |
BlockingQueue<T> |
Además, Exchanger es similar a SynchronousQueue, que también bloquea hasta que ambos hilos estén listos para intercambiar datos. Sin embargo, SynchronousQueue es unidireccional, mientras que Exchanger permite el intercambio mutuo de objetos.
Conclusión
Exchanger es una herramienta útil en Java cuando dos hilos necesitan sincronizarse e intercambiar datos antes de continuar con sus tareas. Es especialmente útil en escenarios como:
- Procesamiento en pasos encadenados donde cada paso es manejado por un hilo diferente.
- Intercambio de buffers en sistemas de procesamiento de datos.
- Simulaciones donde se necesita un mecanismo de sincronización preciso entre hilos.
Para escenarios con más de dos hilos o donde la sincronización no es obligatoria, las colas concurrentes (BlockingQueue) pueden ser una mejor opción.