Alta Concurrencia

When facing high concurrency applications, we often find a number of generic problems. In this article I will focus on the problems of resources (CPU and memory). For now on, I will focus on the most typical and most direct solutions.

When we discover threads and the advantages of parallel processing it can happen that we end up abusing their use. We have a lot of threads (100 ¿? 1000?) simultaneously, and the processor will be jumping from one to another without stopping, not letting them finish, no matter how fast is their real excution. And over time there will be more and more threads only slowing down the process. To the cost of execution of each thread, we must consider also the added cost of creating and destroying threads. It can can become significant when we talk about so many threads at once.

High Concurrency with the Thread Pool Pattern
High Concurrency with the Thread Pool Pattern

Threads: the holy grail

En este caso, al primer método al que debemos recurrir es al Patrón Thread Pool . Este patrón consiste en limitar el número de hilos que hay ejecutándose en un momento dado.
En vez de crear hilos nuevos, creamos tareas, que esperan apiladas. Así mismo, tendremos un pool de hilos que irán cogiendo esas tareas y ejecutándolas lo más pronto posible. Un ejemplo clásico de este patrón se encuentra en la clase SwingWorker. Si queremos implementar "a mano" este patrón, conviene que le echemos un vistazo a la interfaz ExecutorService.

Si tenemos un hilo en background que está haciendo un uso muy intensivo del procesador, pero no nos importa ralentizar su ejecución, podemos hacer uso del comando sleep ( Thread.sleep (...)) to periodically release the thread processor, allowing other threads to run faster .

This is useful for threads running in maintenance mode, which must be kept running but do not have to respond in real time. Another way to temporarily stop a running thread while another is using the method join ( Thread.Join () ), que hace que un hilo espere hasta que el otro hilo termine. Aunque más útil en caso de que tengamos un hilo claramente más prioritario que otro, no es viable si no podemos tener una referencia al hilo más prioritario desde el menos prioritario para indicarle a qué hilo tiene que esperar.

High Concurrency issues

Pero la alta concurrencia no viene dada sólo por el uso del procesador. Puede ocurrir que varios hilos necesiten acceder a grandes cantidades de información de forma casi simultánea. Estos hilos no sólo estarán repitiendo la información en memoria sino que muchas veces estarán repitiendo todo el proceso de extraer dicha información.

Este problema suele estar resuelto en la mayoría de librerías de acceso a datos (base de datos mayormente). Por ejemplo, podemos encontrarnos con el caso de ehcache , que utiliza hilos para almacenar información ( Thread-Specific Storage Pattern ). This way, access and storage of this information is shared. Thus decreasing both the memory usage required and the processor time required to extract and shape information. As the threads wants to process this information, they will be asking ehcache for the data, which will optimize these hits.

Para mejorar esta solución tenemos las colecciones concurrentes. This allow different threads to use the same objects without any problems of concurrency.

There are more solutions to improve the high turnout (without going into optimizations to the code itself). But those described here are usually good ideas to start.

Referencias Útiles:

Easy map on Java

Sometimes you don’t know where to start when you enter the world of GIS programming. Too many libraries, IDEs, but the truth is, everyone assumes you already have a base and everything become chaos. Something is easy as how to develop a map on Java has scarce documentation.

If you have absolutely no idea of GIS, I would recommend you start by the Free book of Free GIS by Victor Olaya.

Para los principiantes yo recomendaría que le echaran un vistazo a un proyecto bastante nuevo que pretende extender Swing (la librería gráfica por excelencia de Java) con widgets geográficos. De esta forma, añadir un mapa a una aplicación de escritorio Java sería una tarea tan sencilla como añadir un botón o un campo de texto.

Por supuesto, para aplicaciones GIS de cierta complejidad, un simple visualizador como este no sería suficiente. Pero es un buen punto de partida para familiarizarnos con lo que es un mapa y las posibilidades que suele ofrecer al desarrollador.

Con un proyecto Java que añada SwingX-WS a sus dependencias, el siguiente código nos mostraría una ventana con un mapa simple:

es.emergya.gis.examples package;

import java.awt.BorderLayout;

public class  SwingWS {

  public static void main (String [] args) {
    Form = new JFrame JFrame ("Map");

    JXMapKit JXMapKit jXMapKit1 = new ();
    jXMapKit1.setDefaultProvider (org.jdesktop.swingx.JXMapKit.DefaultProviders.OpenStreetMaps);
    jXMapKit1.setDataProviderCreditShown (true);
    jXMapKit1.setName ("jXMapKit1") / / NOI18N
    jXMapKit1.setAddressLocation(new GeoPosition(41.881944, 39.627778));

    form.getContentPane().add(jXMapKit1, BorderLayout.CENTER);

    form.pack();
    form.setVisible(true);
  }
}

Las tiles de los mapas los extrae de OpenStreetMap, pero es perfectamente configurable para cualquier servidor WMS.

So now you have your map on java.

Event Listeners Personalizados en Java

Aunque el patrón Observer está implementado nativamente en Java, sometimes we need to make an event management that suits better our needs when using event listeners.

Some context

El problema del manejo de eventos es muy sencillo: Tenemos un objeto que va a ir cambiando de estado. Sin tocar su código, debemos ser capaces de "engancharlo" a otros objetos para que estén pendientes de estos cambios de estado y actúen en consecuencia. Este "enganche" debe poder activarse y desactivarse dinámicamente durante la ejecución.

To implement it we will use a static object, a class and an interface. The static object will be responsible for ensuring the relationships between observers and observables. It will also notify relevant changes to the objects concerned. To pass information during an event we use that class. The interfaces will make the distinction between objects observed and observable objects and any other objects on the application.

A real example

But the best way to see how event listeners works is through an example:

Las instancias de la clase MyCustomEvent serán las que porten la información de un observado a un observable cuando se produzca un evento. Esta clase deberá contener toda la información necesaria sobre ese evento. Por ejemplo, si el evento fuera un click del ratón, esta clase debería llevar datos tales como: coordenadas en la pantalla o el número de clicks. En concreto, nuestra clase de evento sólo contiene el objeto original que lanzó el evento.

import java.util.EventObject;
import java.util.LinkedList;
import java.util.List;

public class MyCustomEvent extends EventObject {

  private static final long serialVersionUID = 7383182229898306240L;

  private final MyCustomListener source;

  public MyCustomEvent (MyCustomListener OriginalSource) {
    super (OriginalSource);
    this.source = OriginalSource;
  }

 MyCustomListener public getSource () {
    this.source return;
  }
}

The static object that keeps the relations between observers and observables is MyCustomEventHandler. It is very important to use synchronization methods to avoid concurrency issues in multithreaded applications:

import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class MyCustomEventHandler {
  private static final Log log = LogFactory.getLog(MyCustomEventHandler.class);

  private static Map <MyCustomListener, Set > = new LinkedHashMap observable <MyCustomListener, Set > ();

  public static void fire (MyCustomEvent event) {
    log.trace ("fire (" + event + ")");
    try {
      Observers = getRemarks September (source);
      if (Observers! = null) {
        for (final MyCustomListener pl: Observers) {
          try {
            pl.fire (event);
          } catch (Throwable t) {
            log.error (t, t);
          }
        }
      }
    } catch (Throwable t) {
      log.error (t, t);
    }
  } 

  private static synchronized September getRemarks (MyCustomListener source) {
    observables.get return (source);
  }

/ **
* Register to watch to alert you when observable change
*
* @ Param observer
* @ Param observable
* /
  public static synchronized void register (MyCustomListener observer, MyCustomListener observable) {
    Observers getRemarks September = (observable);
    if (null == observers) {
      observers = new HashSet();
    }
    observers.add(observer);
    observables.put(observable, Observers);
  }

/ **
* Deregister not become observers to alert you when observable
* Modify
*
* @ Param observer
* @ Param observable
* /
  public static synchronized void deregister (MyCustomListener observer, MyCustomListener observable) {
    Observers getRemarks September = (observable);
    if (null == Observers) {
      Observers = new HashSet ();
    }
    observers.remove (observer);
    observables.put (observable, Observers);
  }
}

Tanto los objetos observables como los objetos observadores tienen que implementar la interfaz MyCustomListener. Esta interfaz obliga a implementar el método fire(MyCustomEvent event) . En los observables, esta función será la encargada de llamar a MyCustomEventHandler. En los observadores, esta función será llamada cuando se lance un evento de su objeto observado.

Actually, it would be convenient to separate the interface into two: one for observers and another for observables. If an object wants to be both observer and observed, it may have problems with this system. But for simplicity for the example we have chosen this implementation.

import java.util.EventListener;

public interface extends EventListener {MyCustomListener
  public void fire (MyCustomEvent event);
}

Si quisiéramos tener diferentes tipos de eventos (parecido a como funciona el MouseListener), lo único que necesitaríamos es ampliar la interfaz MyCustomListener con todas las funcionalidades que queremos que tenga:

import java.util.EventListener;

public interface MyCustomListener extends EventListener {
  public void fireObjectRecycled (MyCustomEvent event);
  public void fireObjectRefreshed (MyCustomEvent event);
  public void fireObjectUpdated (MyCustomEvent event);
}

Así mismo, podríamos usar diferentes clases derivadas de MyCustomEvent para cada una de estas funcionalidades.

We have to modify the static object MyCustomEventHandler to launch the different events.

Referencias: Hilo donde se discute este tipo de implementación de Event Handler