Problem with deadlocks and concurrency Producer Java Consumer

1

I've already been thinking about this problem for a couple of weeks and I always have some error in the concurrency of the threads or that one ends and the other does not, interlock, etc. I post here the summary statement and my code in case someone comes up because I can not solve the mentioned problems. Thank you very much.

The Spanish army, which contains a whopping 100 soldiers (100 threads), is preparing for war after the invasion of Martians occurred during these days. For this, soldiers need a series of weapons that are stored in a chest. The chest has capacity for 10 weapons, which are also numbered with the identifier of each soldier for which said weapon is intended. The gunsmith will place the weapons in the chest as they arrive from the factory to the facilities of our army. In this way, the chest will be filled with weapons that will collect soldiers with the peculiarity that the gunsmith must stop putting weapons in the chest if it is full at this time, as well as the corresponding soldier can not pick up his weapon if the chest is empty.

public class Armero extends Thread{

    private int id_arma;

    private Cofre co;

    /**
     * Get the value of co
     *
     * @return the value of co
     */
    public Cofre getCo() {
        return co;
    }

    /**
     * Set the value of co
     *
     * @param co new value of co
     */
    public void setCo(Cofre co) {
        this.co = co;
    }

    public Armero(Cofre co) {
        id_arma=0;
        this.co=co;
    }

    /**
     * Get the value of id_arma
     *
     * @return the value of id_arma
     */
    public int getId_arma() {
        return id_arma;
    }

    /**
     * Set the value of id_arma
     *
     * @param id_arma new value of id_arma
     */
    public void setId_arma(int id_arma) {
        this.id_arma = id_arma;
    }

    public void run(){
        for(int i=0;i<100;i++){
            id_arma=i;
            co.depositarArma(id_arma);
            try {
                sleep(100);
            } catch (InterruptedException ex) {
                System.out.println("El armero no puede irse a dormir");
            }
        }
    }

}
 public class EjercitoEspañol {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Cofre co= new Cofre();
        Armero a = new Armero(co);
        Soldado s[]=new Soldado[100];


        a.start();

        for(int i=0;i<100;i++){
            s[i]=new Soldado(i,i,co);
        }
        for(int i=0;i<100;i++){
            s[i].start();
        }
        /*for(int i=0;i<100;i++){
            try {
                s[i].join();
            } catch (InterruptedException ex) {
                System.out.println("El soldado " + i + " no puede esperar");
            }
        }*/

        /*try {
            a.join();
        } catch (InterruptedException ex) {
            System.out.println("El armero no puede completar la tarea");
        }*/
    }

}
public class Soldado extends Thread{

    private int id_soldado;
    private int id_arma;
    private Cofre co;

    public Soldado(int id_soldado,int id_arma,Cofre co) {
        this.id_soldado = id_soldado;
        this.id_arma=id_arma;
        this.co=co;
    }


    /**
     * Get the value of id_soldado
     *
     * @return the value of id_soldado
     */
    public int getId_soldado() {
        return id_soldado;
    }

    /**
     * Set the value of id_soldado
     *
     * @param id_soldado new value of id_soldado
     */
    public void setId_soldado(int id_soldado) {
        this.id_soldado = id_soldado;
    }

    public void run(){
        co.retirarArma(id_soldado, id_arma);
        try {
            sleep(50);
        } catch (InterruptedException ex) {
            System.out.println("El soldado " + id_soldado + " no puede irse a dormir");
        }
    }
}
public class Cofre {

    private static int[] cofre;

    private static int cantidadArmas;

    private static boolean lleno;

    private static int pos;

    private static boolean vacio;


    /**
     * Get the value of pos
     *
     * @return the value of pos
     */
    public static int getPos() {
        return pos;
    }

    /**
     * Set the value of pos
     *
     * @param pos new value of pos
     */
    public static void setPos(int pos) {
        Cofre.pos = pos;
    }

    public Cofre() {
        cofre=new int[10];
        for(int i=0;i<cofre.length;i++){
            cofre[i]=-1;
        }
        cantidadArmas=0;
        lleno=false;
        vacio=true;
        pos=0;
    }

    /**
     * Get the value of lleno
     *
     * @return the value of lleno
     */
    public static boolean isLleno() {
        return lleno;
    }

    /**
     * Set the value of lleno
     *
     * @param lleno new value of lleno
     */
    public static void setLleno(boolean lleno) {
        Cofre.lleno = lleno;
    }

    /**
     * Get the value of cantidadArmas
     *
     * @return the value of cantidadArmas
     */
    public static int getCantidadArmas() {
        return cantidadArmas;
    }

    /**
     * Set the value of cantidadArmas
     *
     * @param cantidadArmas new value of cantidadArmas
     */
    public static void setCantidadArmas(int cantidadArmas) {
        Cofre.cantidadArmas = cantidadArmas;
    }

    /**
     * Get the value of cofre
     *
     * @return the value of cofre
     */
    public static int[] getCofre() {
        return cofre;
    }

    /**
     * Set the value of cofre
     *
     * @param cofre new value of cofre
     */
    public static void setCofre(int[] cofre) {
        Cofre.cofre = cofre;
    }

    /**
     * Get the value of cofre at specified index
     *
     * @param index the index of cofre
     * @return the value of cofre at specified index
     */
    public static int getCofre(int index) {
        return cofre[index];
    }

    /**
     * Set the value of cofre at specified index.
     *
     * @param index the index of cofre
     * @param cofre new value of cofre at specified index
     */
    public static void setCofre(int index, int cofre) {
        Cofre.cofre[index] = cofre;
    }

    public synchronized void depositarArma(int id_arma){
        while(lleno){
            try {
                wait();
                System.out.println("El armero esta esperando");
            } catch (InterruptedException ex) {
                System.out.println("Error,el armero no puede esperar");
            }
        }
        cofre[pos]=id_arma;
        System.out.println("El armero ha depositado el arma " + id_arma + " en el cofre en la posicion " + pos);
        cantidadArmas++;
        pos++;
        if(pos==9){
            pos = pos%9;
        }
        if(cantidadArmas==9){
            System.out.println(cantidadArmas + " A ");
            lleno=true;
            vacio=false;
            notify();
        }
    }

    public synchronized void retirarArma(int id,int id_arma){
        while(vacio && cantidadArmas<=0){
            try {
                wait();
                System.out.println("El armero esta esperando");
            } catch (InterruptedException ex) {
                System.out.println("Error,el armero no puede esperar");
            }
        }

        for(int i=0;i<cofre.length;i++){
            if(cofre[i]==id_arma){
                System.out.println("El soldado " + id + " esta retirando su arma con id " + cofre[pos]);
                cofre[i]=-1;
                cantidadArmas--;
            }
        }
        if(cantidadArmas==0){
            System.out.println(cantidadArmas + " S ");
            lleno=false;
            vacio=true;
            notify();
        }

    }

}
    
asked by Alejandro Jimenez Molina 01.05.2018 в 23:41
source

1 answer

1

You have a couple of problems with your current code, just like the logic of depositing and removing weapons are in chest, but with the following problems:

  • The chest should have capacity for 10 weapons, but:

    • The indices to deposit are restricted between 0 and 8.

      if(pos==9){
          pos = pos%9;
      }
      
    • If 9 weapons are deposited, lleno is set in true

      if(cantidadArmas==9){
          System.out.println(cantidadArmas + " A ");
          lleno=true;
          vacio=false;
          notify();
      }
      
    • Only a thread is notified when the chest is full, instead of notifying all threads when there are weapons available li>
  • The soldier only tries to withdraw his weapon once and only waits if the chest is empty, but does not do anything if he does not find his weapon.

    while(vacio && cantidadArmas<=0){
        try {
            wait();
            System.out.println("El armero esta esperando");
        } catch (InterruptedException ex) {
            System.out.println("Error,el armero no puede esperar");
        }
    }
    
  • Only one thread is notified when the chest is emptied, instead of notifying when is not full to all threads

    if(cantidadArmas==0){
        System.out.println(cantidadArmas + " S ");
        lleno=false;
        vacio=true;
        notify();
    }
    

Solving the previous errors and using a list for simplicity instead of an arrangement for the 10 weapons, the coffer code would be like this:

class Cofre {

    private List<Integer> armas;
    private int capacidadMaxima;

    public Cofre(int capacidadMaxima) {
        this.armas = new ArrayList<>(capacidadMaxima);
        this.capacidadMaxima = capacidadMaxima;
    }

    public boolean isLleno() {
        return armas.size() == capacidadMaxima;
    }

    public boolean isVacio() {
        return armas.isEmpty();
    }

    public int getCantidadArmas() {
        return armas.size();
    }

    public synchronized void depositarArma(int id_arma) {
        while (isLleno()) {
            try {
                System.out.println("El armero esta esperando que se vacie el cofre");
                wait();
            } catch (InterruptedException ex) {
                System.out.println("Error, el armero no puede esperar");
            }
        }
        armas.add(id_arma);
        System.out.println("El armero ha depositado el arma " + id_arma + " en el cofre. Cantidad armas: " + getCantidadArmas());
        //notificar a todos los threads que hay armas disponibles
        notifyAll();
    }

    public synchronized void retirarArma(int id_soldado, int id_arma) {
        while (isVacio() || !intentarRetirarArma(id_soldado, id_arma)) {
            try {
                System.out.println("El soldado " + id_soldado + " no encontro su arma. Cantidad armas: " + getCantidadArmas());
                wait();
            } catch (InterruptedException ex) {
                System.out.println("Error, el soldado no puede esperar");
            }
        }
    }

    private synchronized boolean intentarRetirarArma(int id_soldado, int id_arma) {
        for (int i = 0; i < armas.size(); i++) {
            if (armas.get(i) == id_arma) {
                System.out.println("El soldado " + id_soldado + " esta retirando su arma con id " + id_arma);
                armas.remove(i);
                //notificar a todos los threads que se ha retirado un arma (solo al armero le interesa)
                notifyAll();
                return true; //dejar de esperar
            }
        }
        return false; //no encontramos el arma, seguir esperando
    }

}
    
answered by 02.05.2018 / 16:07
source