[Risolto][Java] Esercizio

Linguaggi di programmazione: php, perl, python, C, bash, ecc.

[Risolto][Java] Esercizio

Messaggioda SteveSicily » venerdì 19 maggio 2017, 17:39

Salve sono iscritto in Ing. Informatica e per l'esame di Sistemi Operativi il prof. ha assegnato alcuni esercizi (di esame), tra cui:
Codice: Seleziona tutto
Una pizzeria ha N tavoli che possono ospitare 2, 4 o 6 persone ciascuno, più un tavolo comunitario da 20 posti. I clienti arrivano a gruppi di massimo 10 persone che, chiaramente, non vanno separate. Se possibile, un gruppo viene preferibilmente fatto accomodare in uno dei tavoli piccoli cercando di ottimizzarne l’occupazione
(in altre parole, cercando di lasciare il minor numero possibile di posti vuoti). Altrimenti il gruppo viene fatto accomodare nel tavolo comunitario insieme ad altri gruppi; infine, se nemmeno lì c’è posto, il gruppo viene messo in attesa. Una volta seduti, i clienti di un gruppo ordinano e consumano, impiegando per queste azioni un tempo che può essere simulato di durata casuale, ed infine liberano il tavolo.

Si modelli lo scenario descritto mediante thread in linguaggio Java usando il costrutto monitor e si descriva la sincronizzazione tra thread, discutendo anche se la soluzione proposta può presentare rinvio indefinito o deadlock.


Io ho provato a risolverlo in questo modo:
Codice: Seleziona tutto

//Tavolo.java
public class Tavolo {
    private int id;
    private int posti;
    private int posti_occupati;
   
    public Tavolo(int id, int posti){
        this.id = id;
        this.posti = posti;
        this.posti_occupati = 0;
    }
   
    int getID(){
        return id;
    }
    int getOccupati(){
        return this.posti_occupati;
    }
    int getPosti(){
        return this.posti;
    }
    void setOccupati(int posti_occupati){
        this.posti_occupati = posti_occupati;
    }
}
/*************************************************/

//Gruppo.java

public class Gruppo {
    private int id;
    private int membri;
    private boolean attesa;
    private int id_tavolo;
   
    public Gruppo(int id, int membri){
        this.id = id;
        this.membri = membri;
        this.attesa = true;
        this.id_tavolo = 0;
    }
   
    int getID(){
        return this.id;
    }
   
    int getTavolo(){
        return this.id_tavolo;
    }
   
    void setTavolo(int id_tavolo){
        this.id_tavolo = id_tavolo;
    }
   
    int getMembri(){
        return this.membri;
    }
   
    boolean attesa(){
        return this.attesa;
    }
   
    void attesa(boolean attesa){
        this.attesa = attesa;
    }
}
/******************************************/
//Locale.java


import java.util.LinkedList;
import java.util.Random;

public class Locale implements Runnable {
    private LinkedList<Tavolo> tavoli;
    private LinkedList<Gruppo> gruppi;
    private int group_counter;
    Random r = new Random();
   
    public Locale(){
            for(int i=1; i<=7; ++i){
                tavoli.add(new Tavolo(i, 2));
            }
            for(int i=8; i<=14; ++i){
                tavoli.add(new Tavolo(i, 4));
            }
            for(int i=15; i<=19; ++i){
                tavoli.add(new Tavolo(i, 6));
            }
            tavoli.add(new Tavolo(1, 20));
            group_counter = 1;
    }
   
    public synchronized void creaGruppi(){
        Gruppo g = new Gruppo(group_counter, r.nextInt(10)+1);
        System.out.println("è arrivato il gruppo n°"+g.getID());
        gruppi.add(g);
        ++group_counter;
    }
    public synchronized boolean siedi(){
        for(Tavolo i: tavoli){
            if((i.getPosti() - i.getOccupati()) >= gruppi.getFirst().getMembri()){
                i.setOccupati(gruppi.getFirst().getMembri() + i.getOccupati());
                gruppi.getFirst().attesa(false);
                gruppi.getFirst().setTavolo(i.getID());
                return true;
            }
        }
        return false;
    }
   
    public synchronized boolean alza(){
        if(gruppi.getFirst().getTavolo() == 0){
            System.out.println("è ancora alzato!");
            return false;
        }else{
            int temp = tavoli.get(gruppi.getFirst().getTavolo()).getOccupati();
            tavoli.get(gruppi.getFirst().getTavolo()).setOccupati(gruppi.getFirst().getMembri() - temp);
            System.out.println("Il gruppo "+ gruppi.getFirst().getID() + "è andato via!");
            gruppi.removeFirst();
            return true;
        }
    }
   
    @Override
    public void run(){
        while(true){
            if(gruppi.size() < 20){
                creaGruppi();
                if(!siedi()){
                    System.out.println("Tavoli Occupati!");
                }else{
                    System.out.println("Il gruppo " + gruppi.getFirst().getID() +
                                    " si è seduto al tavolo n°" +
                                     gruppi.getFirst().getTavolo());
                }
                try {
                    Thread.currentThread().sleep(r.nextLong()*1000);
                } catch (Exception e) {
                       e.printStackTrace();
                }
            }else{
                alza();
                if(!siedi()){
                    System.out.println("Tavoli Occupati!");
                }else{
                    System.out.println("Il gruppo " + gruppi.getFirst().getID() +
                                    " si è seduto al tavolo n°" +
                                     gruppi.getFirst().getTavolo());
                }
                try {
                    Thread.currentThread().sleep(r.nextLong()*1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
/*********************************************/
//Main.java


public class Main {
    public static void main(String[] args) {
        Locale r = new Locale();
        Thread t = new Thread(r);
       
        t.start();
    }
}


Volevo sapere se secondo voi va bene, se cè qualcosa nel codice che va scritta meglio ecc.
Un'altra cosa: all'esecuzione mi da questo errore:
Codice: Seleziona tutto
Exception in thread "main" java.lang.NullPointerException
   at Locale.<init>(Locale.java:15)
   at Main.main(Main.java:5)
        Java returned: 1
BUILD FAILED (total time: 0 seconds)



Spero che possiate aiutarmi, grazie in anticipo.
Ultima modifica di SteveSicily il domenica 21 maggio 2017, 1:41, modificato 1 volta in totale.
SteveSicily
Prode Principiante
 
Messaggi: 56
Iscrizione: dicembre 2009

Re: [Java] Esercizio

Messaggioda John_Marco » venerdì 19 maggio 2017, 17:58

Ciao,
Il null pointer è evidente : chiami la add su una lista che non hai inizializzato. Come sai un campo Oggetto definito come
Codice: Seleziona tutto
private Object x;

equivale a
Codice: Seleziona tutto
private Object  x = null;

Ed è per questo che hai una eccezione a Runtime.
Per la logica, ti suggerisco di far girare il programma e vedere se effettivamente fa quel che ti aspetti
John_Marco
Scoppiettante Seguace
Scoppiettante Seguace
 
Messaggi: 256
Iscrizione: maggio 2009
Località: Potenza - Roma
Desktop: Unity
Distribuzione: Ubuntu 16.04 LTS X86_64
Sesso: Maschile

Re: [Java] Esercizio

Messaggioda Gerry Ghetto » venerdì 19 maggio 2017, 18:28

Anche la variabile gruppi ti darà una NPE.

Inoltre non è vietato di scrivere commenti (Javadoc) nel codice. Così sarà più facile sia per te, sia per quelli che fanno un code review.

boolean Gruppo.attesa() non usi mai. O cancellare o cambiare a private.

Perché i metodi creaGruppi(), siedi() e alza() in Locale sono public?
Scusate il mio italiano. Non è la mia madrelingua.
forum.ubuntu-it.org - il peggior forum che conosco
Gerry Ghetto
Entusiasta Emergente
Entusiasta Emergente
 
Messaggi: 1265
Iscrizione: marzo 2015

Re: [Java] Esercizio

Messaggioda SteveSicily » venerdì 19 maggio 2017, 18:59

Gerry Ghetto Immagine ha scritto:Anche la variabile gruppi ti darà una NPE.

Inoltre non è vietato di scrivere commenti (Javadoc) nel codice. Così sarà più facile sia per te, sia per quelli che fanno un code review.

boolean Gruppo.attesa() non usi mai. O cancellare o cambiare a private.

Perché i metodi creaGruppi(), siedi() e alza() in Locale sono public?


Allora per quanto riguarda i commenti solitamente li metto alla fine.
Effettivamente attesa non l'ho usato, alla fine sono riuscito a fare tutto senza di esso!
Li ho messi public, per forza dell'abitudine essendo che per la maggior parte dei casi i metodi devono essere public.

Oltre a questo credi che vada bene?
A cosa è dovuto quel NPE?
SteveSicily
Prode Principiante
 
Messaggi: 56
Iscrizione: dicembre 2009

Re: [Java] Esercizio

Messaggioda SteveSicily » venerdì 19 maggio 2017, 19:02

John_Marco Immagine ha scritto:Ciao,
Il null pointer è evidente : chiami la add su una lista che non hai inizializzato. Come sai un campo Oggetto definito come
Codice: Seleziona tutto
private Object x;

equivale a
Codice: Seleziona tutto
private Object  x = null;

Ed è per questo che hai una eccezione a Runtime.
Per la logica, ti suggerisco di far girare il programma e vedere se effettivamente fa quel che ti aspetti


Scusa l'ho visto ora, si effettivamente non mi tornava sta cosa. :sgrat:
SteveSicily
Prode Principiante
 
Messaggi: 56
Iscrizione: dicembre 2009

Re: [Java] Esercizio

Messaggioda SteveSicily » venerdì 19 maggio 2017, 19:32

Non fa assolutamente quello che mi aspetto, non parte proprio!
Ho modificato una parte così:
Codice: Seleziona tutto
    private final LinkedList<Tavolo> tavoli;
    private LinkedList<Gruppo> gruppi;
    private int group_counter;
    Random r = new Random();
   
   
    public Locale(){
            tavoli = new LinkedList();
            for(int i=1; i<=7; ++i){
                tavoli.add(new Tavolo(i, 2));
            }
            for(int i=8; i<=14; ++i){
                tavoli.add(new Tavolo(i, 4));
            }
            for(int i=15; i<=19; ++i){
                tavoli.add(new Tavolo(i, 6));
            }
            tavoli.add(new Tavolo(1, 20));
            group_counter = 1;
    }
   
    private synchronized void creaGruppi(){
        Gruppo g = new Gruppo(group_counter, r.nextInt(10)+1);
        System.out.println("è arrivato il gruppo n°"+g.getID());
        gruppi.add(g);
        ++group_counter;
    }


Mi da errore alla prima riga del costruttore, come devo inizializzare sta lista?
SteveSicily
Prode Principiante
 
Messaggi: 56
Iscrizione: dicembre 2009

Re: [Java] Esercizio

Messaggioda John_Marco » sabato 20 maggio 2017, 20:42

Perdona la domanda, ma da quanto tempo studi Java?
La lista tavoli è FINAL, il che significa che deve essere inizializzata prima della creazione dell'oggetto. Quindi o togli il final o inizializzi la lista direttamente nella dichiarazione. Ci sarebbe anche la strada di un blocco static di inizializzazione, ma forse non l'avete visto
John_Marco
Scoppiettante Seguace
Scoppiettante Seguace
 
Messaggi: 256
Iscrizione: maggio 2009
Località: Potenza - Roma
Desktop: Unity
Distribuzione: Ubuntu 16.04 LTS X86_64
Sesso: Maschile

Re: [Java] Esercizio

Messaggioda SteveSicily » sabato 20 maggio 2017, 21:11

John_Marco Immagine ha scritto:Perdona la domanda, ma da quanto tempo studi Java?
La lista tavoli è FINAL, il che significa che deve essere inizializzata prima della creazione dell'oggetto. Quindi o togli il final o inizializzi la lista direttamente nella dichiarazione. Ci sarebbe anche la strada di un blocco static di inizializzazione, ma forse non l'avete visto

Codice: Seleziona tutto
    private LinkedList<Tavolo> tavoli= new LinkedList<Tavolo>();
    private LinkedList<Gruppo> gruppi = new LinkedList<Gruppo>();
    private int group_counter;
    Random r = new Random();
   
    public Locale(){
            for(int i=1; i<=7; ++i){
                tavoli.add(new Tavolo(i, 2));
            }
            for(int i=8; i<=14; ++i){
                tavoli.add(new Tavolo(i, 4));
            }
            for(int i=15; i<=19; ++i){
                tavoli.add(new Tavolo(i, 6));
            }
            tavoli.add(new Tavolo(1, 20));
            group_counter = 1;
    }

L'ho modificato così, la situazione è migliorata un po', ma all'esecuzione:
Codice: Seleziona tutto
java.lang.IllegalArgumentException: timeout value is negative
   at java.lang.Thread.sleep(Native Method)
è arrivato il gruppo n°1
Il gruppo 1 si è seduto al tavolo n°1
è arrivato il gruppo n°2
Il gruppo 1 si è seduto al tavolo n°1
   at Locale.run(Locale.java:67)
   at java.lang.Thread.run(Thread.java:745)

Oppure si ferma alla creazione e postazione del primo gruppo.
Qual'è il problema? :cry:
SteveSicily
Prode Principiante
 
Messaggi: 56
Iscrizione: dicembre 2009

Re: [Java] Esercizio

Messaggioda John_Marco » sabato 20 maggio 2017, 23:38

Penso che il problema stia nel fatto che nextLong() possa tornare anche numeri negativi. Ti rimando alla javadoc della classe Random, che tra i metodi ne offre di sicuro almeno uno che fa al caso tuo (cioè che ti restituisce solo numeri positivi).
Oltre a questo, però, ti suggerisco di utilizzare ( e, se non dovessi conoscerlo, a studiare) lo strumento di debug fornito ormai dalla maggior parte degli IDE. In genere fare il debug di una applicazione multithread può essere complicato, ma dal main che hai postato nel primo messaggio mi pare di capire che il thread lanciato è in realtà uno solo.
Per comprendere errori logici o di dati spesso è utile fare una sessione di debug, per vedere quel che accade durante l'esecuzione. Prova, tanti errori all'apparenza incomprensibili vengono poi rapidamente corretti con una sessione di debug.
John_Marco
Scoppiettante Seguace
Scoppiettante Seguace
 
Messaggi: 256
Iscrizione: maggio 2009
Località: Potenza - Roma
Desktop: Unity
Distribuzione: Ubuntu 16.04 LTS X86_64
Sesso: Maschile

Re: [Java] Esercizio

Messaggioda SteveSicily » domenica 21 maggio 2017, 1:40

John_Marco Immagine ha scritto:Penso che il problema stia nel fatto che nextLong() possa tornare anche numeri negativi. Ti rimando alla javadoc della classe Random, che tra i metodi ne offre di sicuro almeno uno che fa al caso tuo (cioè che ti restituisce solo numeri positivi).

Grazie mille a tutti quanti alla fine sono riuscito nel problema, praticamente era esattamente come diceva John_Marco, cioè che nextLong() restituisce numeri negativi, quindi ho sostituito nextLong() con (long)(Math.random()), problema risolto!

Oltre a questo, però, ti suggerisco di utilizzare ( e, se non dovessi conoscerlo, a studiare) lo strumento di debug fornito ormai dalla maggior parte degli IDE. In genere fare il debug di una applicazione multithread può essere complicato, ma dal main che hai postato nel primo messaggio mi pare di capire che il thread lanciato è in realtà uno solo.
Per comprendere errori logici o di dati spesso è utile fare una sessione di debug, per vedere quel che accade durante l'esecuzione. Prova, tanti errori all'apparenza incomprensibili vengono poi rapidamente corretti con una sessione di debug.


Grazie darò un'occhiata!

Grazie ancora a tutti quanti!
SteveSicily
Prode Principiante
 
Messaggi: 56
Iscrizione: dicembre 2009


Torna a Programmazione

Chi c’è in linea

Visualizzano questa sezione: 0 utenti registrati e 5 ospiti