Salta el contingut
 

Exercicis: Programació de fils

Autor: Joan Puigcerver Ibáñez

Correu electrònic: j.puigcerveribanez@edu.gva.es

Llicència: CC BY-NC-SA 4.0

(Reconeixement - NoComercial - CompartirIgual) 🅭

Objectius

Conéixer i implementar programes que creen diferents fils d'execució.

Tots els exercicis han d'estar situats en el package corresponent.

  • Package: ud2.exericises
  • El nom de la classe de cada exercici és el nom.
  • El format de la eixida del programa ha de ser consistent amb el format demanat.

ALotOfThreads

Crea un programa que demane a l'usuari un nombre enter cree aquest nombre de fils.

Cada fil ha de fer:

  • Mostrar un missatge quan comença la seua execució.
  • Esperar aleatòriament entre 1 i 10 segons.
  • Missatge com que esta a punt d'acabar.

Nota

En els dos missatges ha d'aparéixer el nom del fil, que s'assignarà per ordre de creació (FIL1, FIL2, ...)

Entrada

Introdueix els nombre de threads a crear:
3

Eixida

Inici...
FIL1: Comença execució.
FIL2: Comença execució.
FIL3: Comença execució.
FIL1: Acaba execució.
FIL2: Acaba execució.
FIL3: Acaba execució.

FibonacciConcurrent

Crea el programa FibonacciConcurrent que vaja demanant números enters i naturals (majors de 0) a l'usuari. El programa deixarà de demanar números a l'usuari quan s'introduïsca un 0.

Advertència

Utilitzar nombre majors de 40 pot resultar en un overflow de el tipus de dades int.

Si voleu provar amb nombres majors, podeu utilitzar el tipus de dades long.

Per cada número introduït, el programa llançarà un fil que calcule els N primers nombres de Successió de Fibonacci i els mostrarà per pantalla.

Entrada

Introdueix els nombres a calcular:
1 5 30 40 0

Exemple

En aquest cas, el programa llançarà els següents fils:

  • FIL1: Calcula el primer nombre de la successió de Fibonacci.
  • FIL2: Calcula els 5 primers nombres de la successió de Fibonacci.
  • FIL3: Calcula els 30 primers nombres de la successió de Fibonacci.
  • FIL4: Calcula els 40 primers nombres de la successió de Fibonacci.

Eixida

Començant a calcular...
FIL1: Pas 1 de 1: 0
FIL2: Pas 1 de 5: 0
FIL2: Pas 2 de 5: 1
FIL3: Pas 1 de 30: 0
FIL2: Pas 3 de 5: 1
...
...
FIL2: Pas 5 de 5: 3
FIL3: Pas 30 de 30: 832040
FIL4: Pas 40 de 40: 102334155

RunCounterThreads

Crea el programa RunCounterThreads, que llance 4 instàncies de CounterThread, que comptaran des de un nombre inicial fins a un nombre final.

  • Fil 1: Compta de 1 al 10 en 1s de delay.
  • Fil 2: Compta de 10 al 100 en 0.1s de delay.
  • Fil 3: Compta de 25 al 50 en 0.4s de delay.
  • Fil 4: Compta de 1 al 5 en 1.3s de delay.

Cada fil ha de mostrar el següent missatge:

NOM_DEL_FIL: comptador

Eixida

FIL1: 1
FIL2: 10
FIL2: 11
FIL3: 25
FIL2: 12
FIL4: 1
...
...

InterruptCounterThreads

Crea el programa InterruptCounterThreads, que llance 4 instàncies de InfiniteCounterThread, un fil que pot comptar des d'un nombre inicial i no deixarà mai de comptar.

  • Fil 1: Compta a partir del 1 en 1s de delay.
  • Fil 2: Compta a partir del 10 en 0.1s de delay.
  • Fil 3: Compta a partir del 25 en 0.4s de delay.
  • Fil 4: Compta a partir del 1 en 1.3s de delay.

Cada fil ha de mostrar el següent missatge:

NOM_DEL_Fil: comptador

El programa principal comprovarà les següents condicions, i interrompre a cada Thread quan es complisca:

  • Fil 1: Haja comptat fins al 10.
  • Fil 2: Haja comptat fins al 50.
  • Fil 3: Hagen passat 3 segons.
  • Fil 4: Haja comptat 10 números després que el primer fil haja acabat.

Quan s'interromp un fil, ha de mostrar el nom i el comptador.

NOM_DEL_FIL interromput: comptador

SumMatrix

  • Package: ud2.exercises.summatrix

Crea el programa SumMatrix que sume tots els valors d'una matriu d'enters utilitzant un thread per sumar cada fila.

Els valors d'aquesta matriu estan en data_matrix.csv.

Per llegir els valors d'aquest fitxer podeu utilitzar els següent mètode:

public static List<List<Integer>> readMatrixFromCSV(String path) {
    try (BufferedReader br = new BufferedReader(new FileReader(path))) {
        return br.lines()
                .map(
                    x -> Arrays.stream(x.split(","))
                         .mapToInt(Integer::parseInt)
                         .boxed()
                         .toList()
                ).toList();
    } catch (Exception e) {
        System.out.printf("Error reading CSV file: %s\n", path);
    }
    return null;
}

public static void main(String[] args) {
    String CSVPath = "files/ud2/data_matrix.csv";
    List<List<Integer>> matrix = readMatrixFromCSV(CSVPath);

    // TODO

    for(List<Integer> row : matrix){
        // TODO: Create thread
        // TODO: Start thread
    }

    // TODO: Wait for the threads to finish

    // TODO: Sum the result of each thread

    System.out.printf("La suma dels valors en \"%s\" és %d\n", CSVPath, result);

}

Heu de crear la classe SumIntegerListThread, que reba per paràmetre un List<Int> i que sume tots els valors d'aquesta llista en el mètode void run(). Aquesta classe hauria de tindre un atribut int result on se guardarà el resultat de la suma de la llista.

El programa principal SumMatrix, ha de crear un SumIntegerListThread per cada fila de la matriu i llançar els threads.

Quan tots els threads acaben de sumar la seua fila, el fil principal sumarà el resultat de cada fil i mostrarà el resultat.

Eixida

La suma dels valors en "files/ud2/data_matrix.csv" és ?????
Apareixerà la suma en compte de ?????.

ManagerTasks

  • Package: ud2.exercises.tasks

El programa ManagerTasks simula la realització d'un projecte on es coordinen diferents equips de desenvolupament.

El fil principal crea 3 equips, cadascun d'ells liderats per un ManagerThread. Cada equip té uns empleats EmployeeThread, als quals se'ls han assignat unes tasques.

S'han d'implementar els següents mètodes:

  • Task::work(): Aquest mètode defineix com es completa una tasca. Aquest mètode ha d'obtenir el fil actual i fer que espere tants mil·lisegons com s'ha definit en la tasca.

    Aquest mètode imprimirà un missatge quan comence la tasca i quan es finalitze:

    Pere: Starting task Main page design...
    Pere: Finished task Main page design (2500 ms).
    
  • EmployeeThread::run(): Aquest mètode defineix el comportament de cada treballador. Aquest mètode realitzarà totes les tasques que el treballador té assignades.

    Quan acabe totes les tasques, mostrarà el missatge:

    Pere: Ha realitzat totes les tasques assignades.
    

  • ManagerThread::run(): Aquest mètode defineix el comportament del coordinador de l'equip. Aquest mètode posarà a tots els treballador de l'equip a realitzar les seues tasques i esperarà a que les finalitzen.

    Quan tots els treballadors de l'equip acaben les tasques, mostrarà el missatge:

    FrontendManager: L'equip Frontend ha realitzat totes les tasques.
    

  • ManagerTasks::main(): Aquest mètode crea els equips i les tasques, cal acabar-lo perquè cada equip comence a treballar en les tasques assignades. Mostrarà el següent missatge quan tots els equips acaben les seues tasques:

    Projecte acabat! Tots els equips han acabat les tasques assignades.
    

Codi font

ManagerTasks.java
package ud2.exercises.tasks;

public class ManagerTasks {
    public static void main(String[] args) {
        Team frontend = new Team("Frontend");
        ManagerThread frontendManager = new ManagerThread(frontend);

        EmployeeThread f1 = new EmployeeThread("Pere");
        f1.addTask("Main page design", 2500);
        f1.addTask("Shopping cart navigation bar", 5500);
        frontend.addEmployee(f1);

        EmployeeThread f2 = new EmployeeThread("Maria");
        f2.addTask("Breadcrumb", 1500);
        f2.addTask("Profile page", 7500);
        frontend.addEmployee(f2);

        Team backend = new Team("Backend");
        ManagerThread backendManager = new ManagerThread(backend);

        EmployeeThread b1 = new EmployeeThread("Anna");
        b1.addTask("Connect API to database", 3000);
        b1.addTask("Shopping API models", 4200);
        backend.addEmployee(b1);

        EmployeeThread b2 = new EmployeeThread("Arnau");
        b2.addTask("API authentication", 2100);
        b2.addTask("Testing API", 5500);
        backend.addEmployee(b2);

        Team database = new Team("Database");
        ManagerThread databaseManager = new ManagerThread(database);

        EmployeeThread d1 = new EmployeeThread("Mireia");
        d1.addTask("Relation Model", 5000);
        d1.addTask("Define models in the database", 4200);
        database.addEmployee(d1);

        EmployeeThread d2 = new EmployeeThread("Mar");
        d2.addTask("Install DBMS", 3000);
        d2.addTask("Views", 2800);
        database.addEmployee(d2);

        // TODO: Start all the teams and wait for them to finish their tasks

        System.out.println("Projecte acabat! Tots els equips han acabat les tasques assignades.");
    }
}
ManagerThread.java
package ud2.exercises.tasks;

public class ManagerThread extends Thread{
    private Team team;

    public ManagerThread(Team team) {
        super();
        this.team = team;
        this.setName(String.format("%sManager", team.getName()));
    }

    @Override
    public void run() {
        // TODO: Make all your assigned employees do their tasks

        System.out.printf("%s: L'equip %s ha realitzat totes les tasques.\n", this.getName(), team.getName());
    }
}
EmployeeThread.java
package ud2.exercises.tasks;

import java.util.ArrayList;
import java.util.List;

public class EmployeeThread extends Thread{
    private List<Task> tasks;

    public EmployeeThread(String name) {
        super();
        this.setName(name);
        this.tasks = new ArrayList<>();
    }

    public void addTask(Task task) {
        tasks.add(task);
    }
    public void addTask(String taskName, int taskDuration) {
        tasks.add(new Task(taskName, taskDuration));
    }
    public List<Task> getTasks() {
        return tasks;
    }

    @Override
    public void run() {
        // TODO: Do all the assigned tasks

        System.out.printf("%s: Ha realitzat totes les tasques assignades.\n", this.getName());
    }
}
Team.java
package ud2.exercises.tasks;

import java.util.ArrayList;
import java.util.List;

public class Team {
    private String name;
    private List<EmployeeThread> employees;

    public Team(String name) {
        this.name = name;
        employees = new ArrayList<>();
    }

    public void addEmployee(EmployeeThread employee) {
        this.employees.add(employee);
    }

    public List<EmployeeThread> getEmployees() {
        return employees;
    }

    public String getName() {
        return name;
    }
}
Task.java
package ud2.exercises.tasks;

public class Task {
    private int duration;
    private String name;
    boolean finished;

    public Task(String name, int duration) {
        this.name = name;
        this.duration = duration;
        finished = false;
    }

    public int getDuration() {
        return duration;
    }

    public String getName() {
        return name;
    }

    public boolean isFinished() {
        return finished;
    }

    public void setFinished(boolean finished) {
        this.finished = finished;
    }

    public void work(){
        Thread current = Thread.currentThread();
        System.out.printf("%s: Starting task %s...\n", current.getName(), this.name);

        // TODO: Do the task (sleep DURATION miliseconds)

        setFinished(true);
        System.out.printf("%s: Finished task %s (%d).\n", current.getName(), this.name, this.duration);
    }
}