Cliente – Suministrador con Idea
Ejercicio Productor – Consumidor resuelto con IntelliJ Idea 2022.3

El proyecto se llama Cliente-Suministrador
Constantes.java
public class Constantes {
public static final String FICHEROLOG = "ficheroLog.txt";
public static final String INTERCAMBIO = "numeros.txt";
public static final String FICHEROERRORES = "errores.txt";
public static final int REPETICIONES = 10;
//El proyecto se llama Cliente-Suministrador
public static final String CARPETA = "./out/production/Cliente-Suministrador/";
}
Suministrador.java
public class Suministrador {
public static void main(String[] args) throws IOException {
int cuenta = 0;
FileLock bloqueo = null;
RandomAccessFile raf = null;
//Rediregimos la salida y error estándar al fichero de log
try {
PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File(Constantes.FICHEROLOG),true)), true);
System.setOut(ps);
System.setErr(ps);
} catch (FileNotFoundException exp) {
System.out.println(exp.getCause());
exp.printStackTrace();
}
while (cuenta <= Constantes.REPETICIONES) {
try {
raf = new RandomAccessFile(Constantes.INTERCAMBIO, "rwd"); //Abrimos el fichero
//Sección crítica
bloqueo = raf.getChannel().lock();
System.out.println("Suministrador: Entra en la sección");
if (raf.length() == 0) {
int aleatorio = generarNumeroAleatorioEntre(1, 100);
raf.writeInt(aleatorio);
System.out.println("Suministrador: dato escrito " + aleatorio);
cuenta ++;
} else
System.out.println("Suministrador: no puede escribir");
System.out.println("Suministrador: Sale de la sección");
bloqueo.release();
bloqueo = null;
//Fin sección crítica
Thread.sleep(1000); //Simulamos tiempo de creación del dato
} catch (Exception e) {
System.err.println("Suministrador. Error al acceder al fichero.");
System.err.println(e.toString());
} finally {
try {
if (bloqueo != null) bloqueo.release();
if (raf != null) raf.close();
} catch (IOException exp4) {
System.out.println(exp4.getCause());
exp4.printStackTrace();
}
}
}
System.out.println("Suministrador: FIN");
}
private static int generarNumeroAleatorioEntre(int minimo, int maximo) {
return (int) (Math.random() * (maximo + 1 - minimo)) + minimo;
}
}
Cliente.java
public class Cliente {
/**
* @param args Argumento [0] da el número de cliente, lo recibe al lanzarlo con ProcessBuilder
*/
public static void main(String[] args) {
int numeroCliente = Integer.parseInt(args[0]);
RandomAccessFile raf = null;
FileLock bloqueo = null;
int cuenta = 1;
int valor;
//Rediregimos salida y error estándar a un fichero
PrintStream ps = null;
try {
ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File(Constantes.FICHEROLOG),true)), true);
System.setOut(ps);
System.setErr(ps);
} catch (FileNotFoundException exp) {
System.out.println(exp.getCause());
exp.printStackTrace();
}
while (cuenta <= Constantes.REPETICIONES) {// Leemos del fichero las repeticiones realizadas por el suministrador
try {
raf = new RandomAccessFile(Constantes.INTERCAMBIO, "rwd"); //Abrimos el fichero
//Sección crítica
bloqueo = raf.getChannel().lock();
System.out.println("Cliente " + numeroCliente + ": entra en la sección");
if (raf.length() > 0) {
valor = raf.readInt();
System.out.println("Cliente " + numeroCliente + ": lee " + valor);
raf.setLength(0);
cuenta ++;
} else
System.out.println("Cliente: " + numeroCliente + ": no puede leer");
System.out.println("Cliente " + numeroCliente + " sale de la sección");
bloqueo.release();
bloqueo = null;
//Fin sección crítica
Thread.sleep(2000);//simulamos tiempo de procesamiento del dato
} catch (IOException e) {
System.err.println("Cliente " + numeroCliente + ": Error al acceder al fichero.");
System.err.println(e.toString());
} catch (OverlappingFileLockException ex) {
System.err.println("Cliente " + numeroCliente + ": Error en el bloqueo del fichero.");
System.err.println(ex.toString());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
if (bloqueo != null) bloqueo.release();
if (raf != null) raf.close();
} catch (Exception e2) {
System.err.println("Cliente " + numeroCliente + ": Error al cerrar el fichero.");
System.err.println(e2.toString());
System.exit(1); //Si hay error, finalizamos
}
}
}
System.out.println("Cliente " + numeroCliente + " FIN");
}
}
Main.java
public class Main {
public static void main(String[] args) {
//fecha usada para el log de salida
Date fecha = new Date();
SimpleDateFormat formato = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
String hora = formato.format(fecha);
// La lista de los procesos y los contadores
ArrayList<Process> listaProcesos = new ArrayList<>();
int suministrador = 0;
int cliente = 0;
try {// Eliminamos el contenido del fichero al entrar por si tiene un 0
RandomAccessFile fichero = new RandomAccessFile(Constantes.CARPETA + Constantes.INTERCAMBIO, "rwd");
fichero.setLength(0);
fichero.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//Rediregimos salida y error estándar a un fichero, si no la salida de todos los procesos se mezclaría con el menú
try {
PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File(Constantes.CARPETA + Constantes.FICHEROLOG),false)), true);
ps.println("-----------------" + hora + "-----------------------");
} catch (FileNotFoundException exp) {
System.out.println(exp.getCause());
exp.printStackTrace();
}
int opcion = 0;
do {
opcion = mostrarMenuPrincipal(); // Ménu de opciones
switch (opcion) {
case 1:
if (suministrador == 0) { //el suministrador solo se puede lazar una vez
listaProcesos.add(lanzadorProcesos("Suministrador", 1));
suministrador ++;
System.out.println("Suministrador " + suministrador + " lanzado");
} else{
System.out.println("Solo se puede lanzar un Suministrador y ya hay uno ejecutándose");
}
break;
case 2:
cliente ++;
listaProcesos.add(lanzadorProcesos("Cliente", cliente));
System.out.println("Cliente " + cliente + " lanzado");
break;
case 3:
try {
esperarFinalizacion(listaProcesos);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
System.out.println("... procesos finalizados");
System.out.println("Ejecuci\u00f3n finalizada");
break;
}
} while (opcion != 3);
}
/**
* Menú principal de opciones
* @return
*/
private static int mostrarMenuPrincipal() {
int opcion = 1;
boolean leido = false;
int numero = 0;
Scanner teclado = null;
System.out.println (
"\nSeleccione una opci\u00f3n:"
+ "\n1. Lanzar Suministrador"
+ "\n2. Lanzar Cliente"
+ "\n3. Terminar"
+ "\nIndique un número del 1 al 3:"
);
do {
try {
teclado = new Scanner(System.in);
opcion = teclado.nextInt();
leido = true;
} catch (Exception e) {
System.out.println("Error: No es un número entero válido.\n");
}
} while (!leido);
return opcion;
}
/**
* Lanzador de procesos que recibe de entrada un comando y un número usado para diferenciarlos.
* Ejecuta el comando y devuelve un proceso.
*/
public static Process lanzadorProcesos(String comando, int n) {
ProcessBuilder pb ;
Process process = null;
try {
pb = new ProcessBuilder("java",
comando,
String.valueOf(n));
pb.directory(new File(Constantes.CARPETA));
pb.redirectError(new File(Constantes.CARPETA + Constantes.FICHEROERRORES));
process = pb.start();
} catch (IOException e) {
e.printStackTrace();
}
return process;
}
/**
* Recibe una lista de procesos y espera hasta que todos estan cerrados para devolver true
* @param listaProcesos array Process
*/
private static void esperarFinalizacion(ArrayList<Process> listaProcesos) throws InterruptedException {
System.out.print("Procesos en ejecución:\n");
boolean fin = false;
int contador = 0;
if (listaProcesos.size() > 0)
while (!fin) {
contador = 0;
for (Process proceso : listaProcesos) {
if (proceso.isAlive()) {
System.out.println(proceso.info());
contador ++;
System.out.println(contador);
proceso.waitFor(); // Esperar a que termine el proceso
}
if (contador == 0)
fin = true;
}
Thread.sleep(1000);
}
}
}
Para ver en tiempo real el contenido del fichero de log se puede usar en consola el comando tail:
tail -f out/production/Cliente-Suministrador/ficheroLog.txt
Código del Cliente-Suministrador con IntelliJ Idea

Deja una respuesta
Lo siento, debes estar conectado para publicar un comentario.