jueves, 21 de julio de 2011

Trabajando con hilos

Hoy voy a poner un ejemplo de hilos con java, vamos a empezar con un poco de teoría, para crear hilos con java hay dos opciones:
  • Extender de la clase Thread.
  • Implementar la interfaz Runnable.
Mi recomendación es implementar la Interfaz Runnable, ¿Porque? si queremos hacer un pool de hilos para un interfaz las clases tiene que implementar la interfaz Runable. En cualquier caso la opción que elijamos la lógica tiene que escribirse en el método 'run()'. Voy a poner un Ejemplo típico de Productor y Consumidor para ver como crear hilos, despues vamos hacer que sincronizen los hilos para que el productor no ponga  más datos en el buffer cuando este lleno y el consumidor no puedar coger datos cuando esta vacia.

Empezamos vamos a crear un interfaz que se llama Buffer este es su código.

/**
 * Interfaz que permite crear un buffer entre el consumidor y productor
 * @author Xabe
 */
public interface Buffer {
 /**
  * Ponemos un valor en el Buffer
  * @param value
  */
 public void putValue(T value);
 
 /**
  * Obtenemos el valor generico
  * @return 
  */
 public T getValue();
 
 /**
  * Muestra un mensaje de información sobre quien pone un valor
  * @param value
  */
 public void messagePut(T value);
 
 /**
  * Muestra un mensaje de información sobre quien obtiene un valor
  * @param value
  */
 public void messageGet(T value);
}

Ahora vamos implementar el buffer uno sincronizado y otro sin sincronizado.

/**
 * Buffer sin sincronizar
 * @author xabe
 *
 */
public class BufferSinSinconizar implements Buffer {
 private Integer lista[];
 
 /**
  * Construye un array de un elemento para almacenar los datos
  */
 public BufferSinSinconizar() {
  lista = new Integer[] {-1};
 }
 
 
 public Integer getValue() {
  Integer value = lista[0];
  lista[0] = -1;
  messageGet(value);
  return value;
 }

 public void putValue(Integer value) {
  messagePut(value);
  lista[0] = value;
 }
 
 public void messageGet(Integer value) {
  System.out.println("El hilo : "+Thread.currentThread().getName()+" obtiene el valor "+value);
  
 }
 public void messagePut(Integer value) {
  System.out.println("El hilo : "+Thread.currentThread().getName()+" pone el valor "+value);
 }
}
 
La clase buffer sincronizado.
public class BufferSincronizado implements Buffer {
 private Integer lista[];

 public BufferSincronizado() {
  lista = new Integer[] { -1, -1 };
 }

 public synchronized Integer getValue() {
  while (IsBufferVacio()) {
   try {
    System.out.println(Thread.currentThread().getName() + " trata de leer.");
    System.out.println("Bufer vacio.");
    wait();
   }
   // si se interrumpió el subproceso en espera, imprimir el rastreo de
   // la pila
   catch (InterruptedException excepcion) {
    excepcion.printStackTrace();
   }
  }
  int value = -1;
  for (int i = 0; i < lista.length; i++) {
   if (lista[i] != -1) {
    value = lista[i];
    lista[i] = -1;
    break;
   }
  }
  notify();
  messageGet(value);
  return value;
 }

 public synchronized void putValue(Integer value) {
  while (IsBufferLleno()) {
   try {
    System.out.println(Thread.currentThread().getName()
      + " trata de escribir.");
    System.out.println("El Bufer esta lleno.");
    wait();
   } catch (InterruptedException excepcion) {
    excepcion.printStackTrace();
   }
  }
  for (int i = 0; i < lista.length; i++) {
   if (lista[i] == -1) {
    lista[i] = value;
    break;
   }
  }
  messagePut(value);
  notify();
 }

 public boolean IsBufferLleno() {
  boolean lleno = true;
  for (Integer valor : lista) {
   if (valor == -1) {
    lleno = false;
    break;
   }
  }
  return lleno;
 }
 
 public boolean IsBufferVacio() {
  boolean vacio = true;
  for (Integer valor : lista) {
   if (valor > -1) {
    vacio = false;
    break;
   }
  }
  return vacio;
 }

 public void messageGet(Integer value) {
  System.out.println("El hilo : " + Thread.currentThread().getName()
    + " obtiene el valor " + value);

 }

 public void messagePut(Integer value) {
  System.out.println("El hilo : " + Thread.currentThread().getName()
    + " pone el valor " + value);
 }
}
Ahora vamos a poner el código de Consumidor y Productor
public class Consumidor implements Runnable {
 private Thread thread;
 private Buffer buffer;

 public Consumidor(String name, Buffer buffer) {
  this.thread = new Thread(this, name);
  this.buffer = buffer;
 }

 public void run() {
  int suma = 0;
  try {
   for (int cuenta = 1; cuenta <= 4; cuenta++) {
    Thread.sleep((int) (Math.random() * 3001));
    suma += buffer.getValue();
   }
  } catch (InterruptedException excepcion) {
   excepcion.printStackTrace();
  }
  System.out
    .println(thread.getName()
      + " leyo valores, dando un total de: " + suma
      + ".\nTerminando");
 }

 public void start() {
  this.thread.start();
 }

}

public class Productor implements Runnable {
 private Thread thread;
 private Buffer buffer;

 public Productor(String name, Buffer buffer) {
  this.thread = new Thread(this, name);
  this.buffer = buffer;
 }

 public void run() {
  try {
   for (int cuenta = 1; cuenta <= 4; cuenta++) {
    Thread.sleep((int) (Math.random() * 3001));
    buffer.putValue(cuenta);
   }
  } catch (InterruptedException excepcion) {
   excepcion.printStackTrace();
  }
  System.out
  .println(thread.getName()
    + " puso valores"
    + ".\nTerminando");
 }

 public void start() {
  this.thread.start();
 }
}
Por ultimo la clase Main que invoca a los hilos
public static void main(String[] args) {
  Buffer buffer = new BufferSincronizado();
//  Buffer buffer = new BufferSinSinconizar();
  Consumidor consumidor = new Consumidor("Consumidor", buffer);
  Productor productor = new Productor("Productor", buffer);
  productor.start();
  consumidor.start();
 }
Con este ejemplo vemos como se crea hilos y como sincronizar los hilos.

miércoles, 20 de julio de 2011

Usando comando de Java

Vamos hacer un poco de memoria como usar los comandos de java desde consola que nunca viene mal refresca la memoria.

Compilar una clase de java

javac -d target  com/**/*.java

Ejecutar una clase java

java -cp CLASSPATH claseJava

Ejecutar un jar sin manifest

java -cp jar.jar nombreClaseMain

Ejecutar un jar con manifest

java -jar jar.jar nombreClaseMain

Generar un jar

jar -cvf nombreJar.jar .

Generar un jar con manifest

jar -cvfm nombreJar.jar mymaniafest .

Cuando queramos saber más de cada uno de los comandos 'comando -help'

Plugins Maven

En esta entrada nombrare los plugins de maven más usado (por mi) para java como java EE y para hacer documentación y calidad de software . Son los siguientes:
  • Compila el proyecto con versión que deseamos : maven-compiler-plugin
  • Generar jar : maven-jar-plugin
  • Copia las dependencias de nuestro proyecto : maven-dependency-plugin
  • Generar .project y .classpath : maven-eclipse-plugin
  • Codifica los ficheros de src/main/resources : maven-resources-plugin
  • Generar un único jar con todas las dependecias : maven-shade-plugin
  • Generar war : maven-war-plugin
  • Desplegar un proyecto web tomcat : tomcat-maven-plugin
  • Desplegar un proyecto web jetty : maven-jetty-plugin
  • Comprimir javaScript de un proyecto web : yuicompressor-maven-plugin
  • Notificar cambios nuestro proyecto : maven-changes-plugin
  • Generar nuestro informe de CheckStyle : maven-checkstyle-plugin
  • Generar el javaDoc : maven-javadoc-plugin
  • Generar el PMD : maven-pmd-plugin
  • Generar la cobertura : cobertura-maven-plugin
Estos son los plugins que más utilizo actualmente.

viernes, 15 de julio de 2011

Comandos de maven

Hoy vamos a explicar un poco más maven, en esta entrada vamos a explicar los comandos mas utilizado de maven para gestionar nuestro proyectos java.

mvn validate : nos valida nuestro proyecto
mvn clean :  elimina la carpeta target de nuesto proyecto
mvn compile : compila nuestra codigo fuente java
mvn test : nos ejecuta los test de nuestro proyecto
mvn site :  nos genera la documentacion de nuestro proyecto pmd, javadoc, etc..
mvn package :  nos genera jar o war de nuestro proyecto
mvn install :  nos instala nuestro proyecto en nuestro repositorio local
mvn deploy :  nos instala nuestro proyecto en un repositorio remoto

Estos son lo comandos más utilizados.

Los plugins en maven son conjunto de goals, un goal es un ejecución minima. que se puede invocar desde linea de comando o desde pom.xml

mvn plugin:goal

Desde pom.xml entre los tags de <plugins/>

En la siguiente entrada explicaremos el cuerpo de pom.xml más en detalle y tambien los plugins de maven los más utilizados.

martes, 12 de julio de 2011

Primer hola mundo maven

Voy a explicar como crear un proyecto con maven, ver los distintas plantillas que tiene maven para crear proyectos. Abrinos una consola de linux en colocamos en la carpeta que queremos tener nuestro proyecto java, despues ejecutamos el siguiente comando para ver todas la plantillas que tiene maven:

mvn archetype:generate

Esto lo que produce sera un listado de plantillas que tiene maven, por defecto siempre te da el número para crear un proyecto 'maven-archetype-quickstart' en este caso elegimos esta opcion y rellenamos los datos que no piden:
  • groudId : xabe
  • artifactId: holaMundo
  • version: 1.0
  • package: com.xabe
Una vez rellenos los datos no pedira que confirmemos decimos que 'yes' y no crea un carpeta con el valor relleno en artifactId, ahora hacemos nos movemos a la carpeta holaMundo y tenemos la siguiente estructura:

holaMundo
     |_pom.xml
     |_src
            |_main
            |     |_java
            |           |_com
            |                 |_xabe
            |                      |_App.java
            |_test
                  |_java
                        |_com
                              |_xabe
                                   |_AppTest.java

Abrimos el fichero App.java con nuestro editor favorito cambios el Hello World por hola mundo. Una vez realizado el cambio volvemos a la consola ejecutamos el comando:

mvn clean package

 Esto no va crear un carpeta en target donde se va encontrar el jar generado con el siguiente ${artifactId}-{version}.jar en este caso holaMundo-1.0.jar, para ejecutar el el jar invocamos el siguiente comando:

java -classpath holaMundo-1.0.jar com.xabe.App

veremos por pantalla

Hola Mundo

Para poder ejecutar el jar sin indicar  la clase tenemos que modificar el pom.xml para que cuando genere el jar en el Manifest añade el atributo Main-Class añadimos lo siguiente:

<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.3.1</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>com.xabe.App</mainClass>
                        </manifest>
                        <manifestEntries>
                            <mode>development</mode>
                            <url>${project.url}</url>
                            <key>value</key>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>

Cuando ejecutamos otra el vez el comando para generar el jar:

mvn clean package

Y nos vamos a la carpeta target, ejecutamos 

java -jar holaMundo-1.0.jar

Obtenemos el mismo resultado.