[Risolto][Java] Esercizio

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
Scrivi risposta
SteveSicily
Prode Principiante
Messaggi: 58
Iscrizione: mercoledì 30 dicembre 2009, 13:18

[Risolto][Java] Esercizio

Messaggio da SteveSicily »

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.
John_Marco
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 311
Iscrizione: martedì 5 maggio 2009, 19:55
Desktop: Unity
Distribuzione: Ubuntu 16.04 LTS X86_64
Sesso: Maschile
Località: Potenza - Roma

Re: [Java] Esercizio

Messaggio da John_Marco »

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
Gerry Ghetto

Re: [Java] Esercizio

Messaggio da Gerry Ghetto »

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?
SteveSicily
Prode Principiante
Messaggi: 58
Iscrizione: mercoledì 30 dicembre 2009, 13:18

Re: [Java] Esercizio

Messaggio da SteveSicily »

Gerry Ghetto [url=http://forum.ubuntu-it.org/viewtopic.php?p=4983409#p4983409][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] 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: 58
Iscrizione: mercoledì 30 dicembre 2009, 13:18

Re: [Java] Esercizio

Messaggio da SteveSicily »

John_Marco [url=http://forum.ubuntu-it.org/viewtopic.php?p=4983403#p4983403][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] 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: 58
Iscrizione: mercoledì 30 dicembre 2009, 13:18

Re: [Java] Esercizio

Messaggio da SteveSicily »

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?
John_Marco
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 311
Iscrizione: martedì 5 maggio 2009, 19:55
Desktop: Unity
Distribuzione: Ubuntu 16.04 LTS X86_64
Sesso: Maschile
Località: Potenza - Roma

Re: [Java] Esercizio

Messaggio da John_Marco »

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
SteveSicily
Prode Principiante
Messaggi: 58
Iscrizione: mercoledì 30 dicembre 2009, 13:18

Re: [Java] Esercizio

Messaggio da SteveSicily »

John_Marco [url=http://forum.ubuntu-it.org/viewtopic.php?p=4983710#p4983710][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] 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:
John_Marco
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 311
Iscrizione: martedì 5 maggio 2009, 19:55
Desktop: Unity
Distribuzione: Ubuntu 16.04 LTS X86_64
Sesso: Maschile
Località: Potenza - Roma

Re: [Java] Esercizio

Messaggio da John_Marco »

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.
SteveSicily
Prode Principiante
Messaggi: 58
Iscrizione: mercoledì 30 dicembre 2009, 13:18

Re: [Java] Esercizio

Messaggio da SteveSicily »

John_Marco [url=http://forum.ubuntu-it.org/viewtopic.php?p=4983737#p4983737][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] 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!
Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: 0 utenti iscritti e 10 ospiti