Serialización con XML

En ciertas situaciones una forma más prolija de serializar un objeto consiste en convertir su estado en una definicion XML y guardarlo o enviarlo donde haga falta. Esto nos permite poder ver el estado del objeto sobre el stream persistido incluso modificarlo con un editor de texto, cosa impensable sobre la salida de una serializacion estandar. Para tal fin podriamos complicarnos usando XStream o alguno de los tantos OXM (Object XML Mapper) que hay dando vueltas por la red. Calma! Antes de bajar los 20MB de librerias que nos pide el Apache Digester podemos echarle un vistazo a dos clases incluidas en J2SE: XMLEncoder y XMLDecoder.

Estas clases sirven exactamente para nuestros propositos: Transformar objetos en definiciones XML, y definiciones XML en objetos, sin perder nada en el medio. Sin configuraciones ni descriptores extraños estas dos clase son tan faciles de usar como un ObjectInputStream y objectOutputStream.

Objeto -> XML

 Perro p = new Perro();
      FileOutputStream f = new FileOutputStream("perro.xml");
  XMLEncoder xe = new XMLEncoder(f);
      xe.writeObject(p);
      xe.close();

XML -> Objeto

  FileInputStream f = new FileInputStream("perro.xml");
  XMLDecoder xd = new XMLDecoder(f);
      Perro p = (Perro)xd.readObject();

Esta demas decir que el XML contiene todo el grafo del objeto (el perro con sus pulgas, collar, dueño y cualquier otra dependencia) haciendose cargo de forma impecable de las referencias circulares.

Los drawbacks de este metodo si lo comparamos con la serializacion tradicional es el mismo que se le atribuye a RMI vs Webservices: El XML es mas lento y pesado que su par binario. A favor de este método podemos decir que el objeto serializado es un xml que puede editarse en cualquier lado y que se elimina el problema del cambio de version de las clases. Ya no hay que preocuparse por conflictos de versionado con el serialVersionUID porque la unica informacion que se guarda en el xml sobre la clase de las instancias es el nombre.

Contadores Atómicos

Cuanto tiempo sin escribir… en fin. Siempre me llamo la atención que en Java muchas de las operaciones sobre primitivos no son atómicas. El statement c++; por ejemplo no es atómico y puede traernos muchos dolores de cabeza en entornos de multithreading. Vale recordar, consideramos una instrucción como “atómica” si no puede ser interrumpida para darle paso a otro thread. En el siguiente ejemplo se presentan el caso de dos threads que consumen concurrentemente un contador. Si ejecutan el código podrán ver que no se obtiene el resultado esperado.

public class Main {

public static void main(String[] args) {
Contador c = new Contador();
new Corredor(c).start();
new Corredor(c).start();
}
}

class Corredor extends Thread {

private Contador contador;

@Override
public void run() {

for (int i = 0; i < 20; i++) {
try {
System.out.println(contador.incrementAndGet());
Thread.sleep(500);
} catch(Exception e) {
}
}

}

public Corredor(Contador contador) {
this.contador = contador;
}
}

class Contador {

private int value = 0;

public int incrementAndGet() {
return ++value;
}
}

En la pantalla terminamos con algo parecido a

1 2 2 3 3 4 4 5 6 6 7 7 8 8 9 9 10 10 11 ……

De alguna forma estamos forzando un poco esa situacion poniendo a dormir el Thread luego de llamar al metodo incrementAndGet() pero es una situacion que perfectamente se puede dar cuando hay muchos threads en ejecución. Podriamos corregir esta situación synchronizando el metodo incrementAndGet() pero produciría una sobrecarga que quizá no estemos dispuestos a pagar.

java.util.concurrent.atomic.AtomicInteger es la clase que vamos a usar para solucionar este problema. AtomicInteger se comporta como un Integer comun y corriente pero es mutable a traves de metodos atómicos. Lo mejor es que los metodos no son sincronizados de forma tradicional sino por otras oscuras tecnicas que en su momento trataré. Esta clase posee metodos tales como addAndGet(int delta) que incrementa en un delta de forma atomica, decrementAndGet(), getAndAdd(), getAndIncrement() y muchos otros que hacen más o menos lo que indican los nombres pero siempre siempre de forma atómica.

Más información en http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/atomic/AtomicInteger.html

Entradas y comentarios feeds. 13 queries. 0.869 seconds.

60921 pages viewed, 16 today
29270 visits, 11 today
FireStats icon Powered by FireStats