How to control multithreading in parallelism?

Asked

Viewed 181 times

2

I’ve tried using the methods wait() with notify and even the depreciated methods stop(), and did not succeed.

I have three (3) threads which are:

Tankcontroller

Faucetfill

Faucetempty

What I’m trying to do is simply this:

a) Tankcontroller controls Faucetfill and Faucetempty threads.

b) Faucetfill has a water flow rate of 10 liters every 150ms.

c) Faucetempty has a water flow rate of 30 liters every 150ms.

How Tankcontroller Works?

a) The tank controller is responsible for opening and closing the taps.

b) When the tank reaches its maximum volume, the tap filler is closed and the tap emptying is opened.

c) When the tank is below 50% of its volume the filling tap shall be opened.

d) When the volume of water is below the tap, the tap shall be turned off.

What problem I’m having?

I cannot properly manipulate the Faucetfill and Faucetempty threads within the Tankcontroller thread to be able to open and close the tap in its particular condition.

Main java.

public class Main {

    public static void main(String[] args) {
        Tank t = new TankWater();
        FaucetFill ff = new FaucetFill(t);
        FaucetEmpty fe = new FaucetEmpty(t);
        TankController tc = new TankController(t, ff, fe);
    
        ff.start();
        fe.start();
        tc.start();
    }

}

Tankcontroller.java

public class TankController extends Thread {
    private final TankWater tank;
    private final FaucetFill ff;
    private final FaucetEmpty fe;
    
    public TankController(Tank t, FaucetFill ff, FaucetEmpty fe) {
        this.tank = t;
        this.ff = ff;
        this.fe = fe;
    }
    
    @Override
    public void run() {
        System.out.println("TANK-CONTROLLER RUNNING!");
        
        // CÓDIGO DE CONTROLE DAS TORNEIRAS
    
    }

}

Faucetfill.java

public class FaucetFill extends Thread {
    private final TankWater tank;
    private final int timer = 150;
    private int litersWater = 10;
    private boolean isStarted;
    
    public FaucetFill(Tank t) {
        this.tank = t;
    }
    
    public void setIsStarted(boolean state) {
        this.isStarted = state;
    }
    
    @Override
    public void run() {
        while(this.isStarted) {
            System.out.println("FAUCETFILL RUNNING");
            Thread.currentThread().sleep(this.timer);
            this.tank.setAmountWater(this.litersWater);
        }
     
    }
}

Faucetempty.java

public class FaucetEmpty extends Thread {
    private final TankWater tank;
    private final int timer = 150;
    private int litersWater = 30;
    private boolean isStarted;
    
    public FaucetEmpty(Tank t) {
        this.tank = t;
    }
    
    public void setIsStarted(boolean state) {
        this.isStarted = state;
    }
    
    @Override
    public void run() {
        while(this.isStarted) {
            System.out.println("FAUCETEMPTY RUNNING");
            Thread.currentThread().sleep(this.timer);
            this.tank.removeWater(this.litersWater);
        }
        
    }

}

Tankwater.java.

import java.math.BigDecimal;

public class TankWater {
    private final int maximumCapacity = 2000;
    private int amountWater = 0;
    
    public int getAmountWater() {
        return amountWater;
    }
    
    public void setAmountWater(int amountWater) {
        if(this.getPercentageWater() != 100)
            this.amountWater += amountWater;
    }
    
    public void removeWater(int quantity) {
        if(this.getAmountWater() - quantity >= 0)
            this.setAmountWater(this.getAmountWater() - quantity);
    }
    
    public double getPercentageWater() {
        BigDecimal value = new BigDecimal(this.maximumCapacity);
        BigDecimal rate  = new BigDecimal(this.getAmountWater());
        BigDecimal percentage = rate.divide(value).multiply(new BigDecimal("100"));
        
        return percentage.doubleValue();
    }    
}
  • Thiago, you can as an alternative implement the Singleton standard in your main and your threads monitor the main class, it would be kind of an inverted control, I believe have better ways to circumvent, but it works in practice.

  • TankWater does not extend Thread, because you say that it is a Thread? From what I see it is accessed by Threads. Also note that your setAmountWater(int amountWater) does not protect the tank from "overflowing" (even if the tank is empty and you pass as argument 3000 the tank will be with 3 thousand liters, well above the capacity and therefore in an inconsistent state); this problem will also occur if it is with some 1995 liters and the FaucetFill add +10 liters, it goes to 2005 liters.

  • @Douglas on the Tankwater is fixed, really it is not a Thread. The other questions I corrected and got the answer algorithm I gave below.

1 answer

1


I was able to manipulate the parallelism with the multithreading and all the information cited in my question. Below is my code and an animation of the output.

Output [Animation] inserir a descrição da imagem aqui Java console.

import java.io.IOException;

public class Console {
    private static final ProcessBuilder process = new ProcessBuilder("cmd", "/c", "cls");

    public static void clearScreen() {  
        try {
            process.inheritIO().start().waitFor();
        } catch(IOException | InterruptedException e) {}  
    } 
}

Main java.

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        TankWater tw = new TankWater();
        FaucetFill ff = new FaucetFill(tw);
        FaucetEmpty fe = new FaucetEmpty(tw);
        TankWaterController twc = new TankWaterController(tw, ff, fe);

        System.out.println("Para iniciar a simulação tecle ENTER ou CTRL+C para finalizar");
        input.nextLine();

        twc.init();
        input.nextLine();
    }

}

Faucetempty.java

public class FaucetEmpty extends Thread {
    private final TankWater tankWater;
    private boolean isOpen;
    private int literOfWater = 30;
    private long timer = 150;

    public FaucetEmpty(TankWater tw) {
        this.tankWater = tw;
        this.isOpen = false;
    }

    public synchronized void open() {
        this.isOpen = true;
    }

    public synchronized void close() {
        this.isOpen = false;
    }

    public synchronized boolean isOpen() {
        return this.isOpen;
    }

    @Override
    public void run() {
        while(!interrupted()) {
            if(this.isOpen)
                this.tankWater.removeWater(this.literOfWater);

            try {
                Thread.sleep(150);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}

Faucetfill.java

public class FaucetFill extends Thread {
    private final TankWater tankWater;
    private boolean isOpen;
    private int literOfWater = 10;
    private long timer = 150;

    public FaucetFill(TankWater tw) {
        this.tankWater = tw;
        this.isOpen = false;
    }

    public synchronized void open() {
        this.isOpen = true;
    }

    public synchronized void close() {
        this.isOpen = false;
    }

    public synchronized boolean isOpen() {
        return this.isOpen;
    }

    @Override
    public void run() {
        while(!interrupted()) {
            if(this.isOpen)
                this.tankWater.fillWater(this.literOfWater);

            try {
                Thread.sleep(150);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

Scene java.

public class Scene {
    private boolean tankMatrix[][];
    private final TankWater tankWater;
    private final FaucetFill faucetFill;
    private final FaucetEmpty faucetEmpty;

    public Scene(TankWater tw, FaucetFill ff, FaucetEmpty fe) {
        this.tankMatrix = new boolean[10][20];
        this.tankWater = tw;
        this.faucetFill = ff;
        this.faucetEmpty = fe;
    }

    public synchronized void updateTankWater() {
        int volumeWater = this.tankWater.getCurrentWaterVolume() / 10;

        for(int line = 9; line >= 0; line--) {
            for(int column = 0; column < 20; column++) {
                if(volumeWater > 0) {
                    this.tankMatrix[line][column] = true;
                    volumeWater--;
                } else {
                    this.tankMatrix[line][column] = false;
                }
            }
        }

        if(this.faucetFill.isOpen()) {
            for(int line = 9; line >= 0; line--)
                this.tankMatrix[line][8] = true;
        }
    }

    public synchronized void printScene() {
        int line;

        Console.clearScreen();
        System.out.println(this.tankWater.getCurrentWaterVolume());
        System.out.println("----------+");
        System.out.println("oooooooooo|");
        System.out.println("--------+o|");
        System.out.println("        |o|");

        if(this.faucetFill.isOpen()) {
            System.out.println("        +o+");
            System.out.println("         o");
        } else {
            System.out.println("        +-+");
            System.out.println();
        }

        for(line = 0; line < 5; line++) {
            System.out.print("|");

            for(int column = 0; column < 20; column++) {
                System.out.print(this.tankMatrix[line][column] ? 'o' : ' ');
            }

            System.out.println("|");
        }

        System.out.print("|");

        for(int column = 0; column < 20; column++) {
            System.out.print(this.tankMatrix[line][column] ? 'o' : ' ');
        }

        System.out.println("+------+");
        line++;
        System.out.print("|");

        for(int column = 0; column < 20; column++) {
            System.out.print(this.tankMatrix[line][column] ? 'o' : ' ');
        }

        System.out.println(this.faucetEmpty.isOpen() ? "ooooooo|" : "|oooooo|");
        line++;
        System.out.print("|");

        for(int column = 0; column < 20; column++) {
            System.out.print(this.tankMatrix[line][column] ? 'o' : ' ');
        }

        System.out.println("+----+o|");
        line++;
        System.out.print("|");

        for(int column = 0; column < 20; column++) {
            System.out.print(this.tankMatrix[line][column] ? 'o' : ' ');
        }

        if (this.faucetEmpty.isOpen()) {
            System.out.println("|    +o+");
        } else {
            System.out.println("|    +-+");
        } 

        line++;
        System.out.print("|");

        for(int column = 0; column < 20; column++) {
            System.out.print(this.tankMatrix[line][column] ? 'o' : ' ');
        }

        System.out.print('|');

        if(this.faucetEmpty.isOpen()) {
            System.out.print("     o");
        }

        System.out.print("\n+--------------------+");

        if(this.faucetEmpty.isOpen()) {
            System.out.println("     o");
        } else {
            System.out.println();
        }

        System.out.println("\n\nPara parar a simulação aperte a tecla CTRL+C.");
    }


}

Tankwater.java.

public class TankWater {
    private final int maximumWaterVolume = 2000;
    private int currentWaterVolume = 0;

    public synchronized int getCurrentWaterVolume() {
        return this.currentWaterVolume;
    }

    public synchronized void fillWater(int litersOfWater) {
        this.currentWaterVolume += litersOfWater;
    }

    public synchronized void removeWater(int litersOfWater) {
        if(this.currentWaterVolume >= litersOfWater)
            this.currentWaterVolume -= litersOfWater;
        else 
            this.currentWaterVolume = 0;
    }
}

Tankwatercontroller.java

public class TankWaterController extends Thread {
    private final TankWater tankWater;
    private final FaucetFill faucetFill;
    private final FaucetEmpty faucetEmpty;  
    private final Scene scene;

    public TankWaterController(TankWater tw, FaucetFill ff, FaucetEmpty fe) {
        this.tankWater = tw;
        this.faucetFill = ff;
        this.faucetEmpty = fe;
        this.scene = new Scene(this.tankWater, this.faucetFill, this.faucetEmpty);
    }

    public void init() {
        this.faucetFill.start();
        this.faucetEmpty.start();
        start();
    }


    @Override
    public void run() {
        while(!interrupted()) {
            if(this.tankWater.getCurrentWaterVolume() <= 1000)
                this.faucetFill.open();
            if(this.tankWater.getCurrentWaterVolume() >= 2000) {
                this.faucetFill.close();
                this.faucetEmpty.open();
            }

            if(this.tankWater.getCurrentWaterVolume() <= 600)
                this.faucetEmpty.close();

            this.scene.updateTankWater();
            this.scene.printScene();
        }
    }
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.