Hilos en java sin heredar de Thread

Uno de mis amigos está ahora cursando la asignatura de Redes. En las prácticas usan Java e inevitablemente hacen uso de hilos. Hasta ahí todo normal. El problema (por llamarlo de alguna manera) es que los ejemplos disponibles en las transparencias crean clases que extienden de Thread.

Crear un hilo heredando de Thread me parece una idea poco aconsejable ya que Java no soporta herencia múltiple. Vamos, que si implementas hilos heredando de Thread tienes que decirle adiós a heredar de cualquier otra clase. Para evitarlo Java proporciona la interfaz Runnable.

A continuación voy a poner tres enunciados y un posible implementación sin recurrir a la herencia. Obviamente son sólo ejemplos y habrá muchas variantes que puedan ser correctas.

Ejercicio 1:

Realizar un programa con 4 hilos. Cada uno de ellos mostrará 5 mensajes por pantalla indicando su nombre y la hora actual. Después de cada acceso a la pantalla se dormirán 1000 milisegundos.

import java.text.SimpleDateFormat;
import java.util.Calendar;
 
public class FirstExample {
 
	public FirstExample() {
		for (int i = 1; i < 5; i++)
			new Thread(new ThreadHello("Hilo " + i)).start();
	}
 
	public static void main(String[] args) {
		new FirstExample();
	}
 
	class ThreadHello implements Runnable {
		private String name;
 
		public ThreadHello(String name) {
			this.name = name;
		}
 
		@Override
		public void run() {
			for (int i = 0; i < 5; i++) {
				System.out.println(name + " - " + new SimpleDateFormat("HH:mm:ss").format(Calendar.getInstance().getTime()));
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

Ejercicio 2:

Simular una cuanta bancaria con dos hilos. Uno simulará el ingreso y el otro la extracción de dinero de la cuenta. La cuenta tendráun capital inicial. Realizar 10 ingresos y 5 extracciones.

public class CuentaBancaria {
 
	private int saldo;
 
	private static CuentaBancaria INSTANCE = null;
 
	private CuentaBancaria(int saldoInicial) {
		saldo = saldoInicial;
	}
 
	public synchronized static CuentaBancaria getInstance(int saldo) {
		if (INSTANCE == null)
			INSTANCE = new CuentaBancaria(saldo);
		return INSTANCE;
	}
 
	public static CuentaBancaria getInstance() {
		return INSTANCE;
	}
 
	public synchronized void ingresar(int cantidad) {
		saldo += cantidad;
		System.out.println("Ingreso realizado. El nuevo saldo es: " + saldo);
	}
 
	public synchronized void extraer(int cantidad) {
		saldo -= cantidad;
		System.out.println("Extracción realizada. El nuevo saldo es: " + saldo);
	}
}
public class ThreadExtraer implements Runnable {
	private int cantidad;
 
	public ThreadExtraer(int cantidad) {
		this.cantidad = cantidad;
	}
 
	@Override
	public void run() {
		CuentaBancaria.getInstance().extraer(cantidad);
	}
}
public class ThreadIngresar implements Runnable {
	private int cantidad;
 
	public ThreadIngresar(int cantidad) {
		this.cantidad = cantidad;
	}
 
	@Override
	public void run() {
		CuentaBancaria.getInstance().ingresar(cantidad);
	}
}
public class Main {
 
	public Main() {
		CuentaBancaria.getInstance(10000);
		for (int i = 0; i < 5; i++)
			new Thread(new ThreadExtraer(1000)).start();
		for (int i = 0; i < 10; i++)
			new Thread(new ThreadIngresar(500)).start();
	}
 
	public static void main(String[] args) {
		new Main();
	}
}

Ejercicio 3:

Realizar un programa que lea frases por teclado hasta que se introduzca una línea con la palabra fin y lo grabe en un fichero. Se diseñarán dos hilos, uno se encargará de la lectura de las frases y el otro de la grabación del fichero.

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
 
public class Controller {
 
	private static Controller INSTANCE = null;
 
	private Controller() {
		new Thread(new ThreadReader()).start();
	}
 
	public void writeToFile(String text) {
		new Thread(new ThreadWriter(text)).start();
	}
 
	public synchronized static Controller getInstance() {
		if (INSTANCE == null)
			INSTANCE = new Controller();
		return INSTANCE;
	}
 
	public class ThreadReader implements Runnable {
 
		@Override
		public void run() {
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			String line, text = "";
			try {
				while ((line = br.readLine()).toLowerCase().compareTo("fin") != 0)
					text += line + "\r\n";
			} catch (IOException e) {
				e.printStackTrace();
			}
			Controller.getInstance().writeToFile(text);
		}
	}
 
	public class ThreadWriter implements Runnable {
 
		private String text;
 
		public ThreadWriter(String text) {
			this.text = text;
		}
 
		@Override
		public void run() {
			try {
				PrintWriter pw = new PrintWriter(new File("data.txt"));
				pw.println(text);
				pw.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
 
	}
}
public class Main {
 
	public static void main(String[] args) {
		Controller.getInstance();
	}
 
}

Supongo que la pregunta es, ¿qué haríais vosotros?

About the Author

Me llamo Pablo Carballude González, soy graduado en computación con master en HCI y Seguridad Informática. Actualmente trabajo para Amazon en Seattle como Software Developer Engineer. Soy de esas personas que no saben si los textos autobiográficos deben ser en primera o tercera persona. Lo intenté en segunda, pero no le entendí nada :P