En el inicio de los tiempos (para Java) habían dos formas de crear hilos:
-
La primera forma de crear un thread es simplemente extender la clase “Thread”.
public class ThreadExample extends Thread { public ThreadB() { super("ThreadB"); } public void run() { //Code } } //crea un objeto "threadExample". //usa "threadExample.start()" para iniciar el hilo. -
La segunda forma es implementar la interfaz “Runnable”.
public class RunnableExample implements Runnable { public void run() { //Code } } //crea un objeto "runnableExample". //usa "new Thread(runnableExample).start()" para iniciar el hilo.
¿Cúal de las dos formas es preferible?
La segunda forma es preferible, ya que el hecho de implementar una interface no impide extender de otra clase (o implementar otras interfaces). La composición (“composition”) es el camino “purista” a seguir. esto permite un bajo acoplamiento y da libertad de a futuro poder cambiar la forma de iniciar los hilos.
Pero… eso era el Java de antes.
Actualmente es más recomendable usar las nuevas funcionalidades proporcionada para el manejo de hilos. Es más recomendable el uso de Callables y FutureTasks. El soporte para los tiempos de espera (timeouts), para la cancelación y el manejo del conjunto de hilos (thread pooling), y las nuevas funciones de concurrencia son mucho más útiles que manejar montones de hilos en crudo y ser uno mismo el que implemente ese manejo.
La interfaz Callable es muy parecida a Runnable, con la diferencia que Callable permite devolver un objeto de la ejecución del método call (que funciona similar al run de Runnable).
Notar que Callable es una interfaz tipada, en este caso pongo un ejemplo con el tipo Object, pero bien se pudo definir el tipo de dato a regresar por call como String, Integer, o lo que desees.
//El tipado debe ser definido por el tipo de resultado de call: Callableprivate class CallableExample implements Callable
Para usos prácticos esto significa que yo estoy esperando una respuesta de Callable y que seguramente eso se traducirá en tareas síncronas:
//Colección para mantener una liga a todas las tareas Collectiontasks = new ArrayList (); //creando cada tarea CallableExample yt1 = new CallableExample(); //Creando más tareas... //Agregando tareas a la colección tasks.add(yt1); //Agregando más tareas... //Usar el ejecutor: ExecutorService exec = Executors.newFixedThreadPool(5); //La lista de respuesta debe ser del tipo: List > List > results = exec.invokeAll(tasks);
En el caso de tareas de las cuales no esperamos una respuesta, usamos la interfaz Runnable. Seguramente eso está ligado a tareas asíncronas.
/* Get an executor service that will run a maximum of 5 threads at a time: */
ExecutorService exec = Executors.newFixedThreadPool(5);
/* For all the 100 tasks to be done altogether... */
for (int i = 0; i < 100; i++) {
/* ...execute the task to run concurrently as a runnable: */
exec.execute(new Runnable() {
public void run() {
/* do the work to be done in its own thread */
System.out.println("Running in: " + Thread.currentThread());
}
});
}
/* Tell the executor that after these 100 steps above, we will be done: */
exec.shutdown();
try {
/* The tasks are now running concurrently. We wait until all work is done,
* with a timeout of 50 seconds: */
boolean b = exec.awaitTermination(50, TimeUnit.SECONDS);
/* If the execution timed out, false is returned: */
System.out.println("All done: " + b);
} catch (InterruptedException e) { e.printStackTrace(); }
Espero esto te sea de ayuda.
Algunas de las páginas que visité para hacer esta entrada fueron:
- Creación y control de threads
- Java: "implements Runnable" vs. "extends Thread"
- How to implement simple threading in Java

