Salta el contingut
 

Exercicis: Programació de fils

Joan Puigcerver Ibáñez

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.exercises.
  • Nom de la classe: el nom de cada exercici.
  • Format de l'eixida: ha de ser consistent amb el format demanat.

ALotOfThreads

Crea un programa que demane a la persona usuària un nombre enter i cree aquest nombre de fils.

Cada fil ha de fer el següent:

  • Mostrar un missatge quan comença la seua execució.
  • Esperar un temps aleatori entre 1 i 10 s mitjançant el mètode Thread.sleep().
  • Mostrar un missatge quan està a punt d'acabar.

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

Entrada

Introdueix el nombre de fils 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 a la persona usuària nombres enters i naturals (majors de 0). El programa deixa de demanar nombres quan s'introdueix un 0.

Per cada nombre introduït, el programa ha de llançar un fil que calcule els N primers nombres de la successió de Fibonacci – Viquipèdia i els mostre per pantalla.

Utilitzar nombres majors de 40 pot provocar un desbordament del tipus de dades int.

Si vols provar amb nombres majors, pots utilitzar el tipus de dades long.

Entrada

Introdueix els nombres a calcular:
1 5 30 40 0
Exemple: Fils llançats amb l'entrada anterior

Amb l'entrada anterior, el programa llança els fils següents:

  • 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, les quals compten des d'un nombre inicial fins a un nombre final:

  • Fil 1: compta de 1 a 10 amb un retard d'1 s.
  • Fil 2: compta de 10 a 100 amb un retard de 0,1 s.
  • Fil 3: compta de 25 a 50 amb un retard de 0,4 s.
  • Fil 4: compta de 1 a 5 amb un retard d'1,3 s.

Cada fil ha de mostrar el missatge següent:

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 compta des d'un nombre inicial i no deixa mai de comptar:

  • Fil 1: compta a partir de l'1 amb un retard d'1 s.
  • Fil 2: compta a partir del 10 amb un retard de 0,1 s.
  • Fil 3: compta a partir del 25 amb un retard de 0,4 s.
  • Fil 4: compta a partir de l'1 amb un retard d'1,3 s.

Cada fil ha de mostrar el missatge següent:

NOM_DEL_FIL: comptador

El programa principal ha de comprovar les condicions següents i interrompre cada fil quan es complisca la seua:

  • Fil 1: haja comptat fins al 10.
  • Fil 2: haja comptat fins al 50.
  • Fil 3: hagen passat 3 s.
  • Fil 4: haja comptat 10 nombres després que el primer fil haja acabat.

Consulta com calcular el temps transcorregut en Java.

Quan s'interromp un fil, ha de mostrar el seu 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 fil per sumar cada fila. Els valors de la matriu estan en data_matrix.csv.

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

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);
}

Crea la classe SumIntegerListThread, que reba per paràmetre un List<Integer> i que sume tots els valors d'aquesta llista en el mètode void run(). Aquesta classe ha de tindre un atribut int result on es guarde el resultat de la suma.

El programa principal SumMatrix ha de crear un SumIntegerListThread per cada fila de la matriu i llançar els fils. Quan tots els fils acaben de sumar la seua fila, el fil principal ha de sumar el resultat de cada fil i mostrar-ne el total.

Eixida

La suma dels valors en "files/ud2/data_matrix.csv" és ?????

En lloc de ????? ha d'aparéixer la suma.

ManagerTasks

  • Package: ud2.exercises.tasks.

El programa ManagerTasks simula la realització d'un projecte en el qual es coordinen diferents equips de desenvolupament. El fil principal crea 3 equips, cadascun liderat per un ManagerThread. Cada equip té unes persones empleades (EmployeeThread), a les quals s'han assignat unes tasques.

Implementa els mètodes següents:

  • Task::work(): defineix com es completa una tasca. Ha d'obtindre el fil actual i fer que espere tants mil·lisegons com s'han definit en la tasca. A més, ha d'imprimir un missatge quan comença la tasca i quan acaba:

    Pere: Starting task Main page design...
    Pere: Finished task Main page design (2500 ms).
    
  • EmployeeThread::run(): defineix el comportament de cada persona empleada. Ha de realitzar totes les tasques que té assignades i, quan les acabe, mostrar el missatge:

    Pere: Ha realitzat totes les tasques assignades.
    
  • ManagerThread::run(): defineix el comportament de la persona coordinadora de l'equip. Ha de posar totes les persones empleades de l'equip a realitzar les seues tasques i esperar que les finalitzen. Quan totes acaben, ha de mostrar el missatge:

    FrontendManager: L'equip Frontend ha realitzat totes les tasques.
    
  • ManagerTasks::main(): crea els equips i les tasques. Cal completar-lo perquè cada equip comence a treballar en les tasques assignades. Ha de mostrar el missatge següent 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);
    }
}
📌 Aquest document pot quedar desactualitzat després d’imprimir-lo. Pots consultar la versió més recent a la pàgina web.
🌿 Abans d’imprimir aquest document, considera si és realment necessari. Redueix el consum de paper i ajuda a protegir el nostre entorn.