Ciao a tutti io ho questo codice in un oggetto in comune (UfficioPostale) tra due thread Cliente e Impiegato.
All'avvio faccio scegliere all'utente quanti impiegati ci sono e quanti clienti, ogni cliente effettua delle richieste create a random tra B, E, A e P.
Il problema è che l'output del tempo medio di attesa non è esatto ovvero:
codice:
La media d'attesa per la richiesta B è di: 1242 ms con 23 richieste
La media d'attesa per la richiesta E è di: -201184639937 ms con 13 richieste
La media d'attesa per la richiesta A è di: -150888478608 ms con 26 richieste
La media d'attesa per la richiesta P è di: -217950025263 ms con 18 richieste
e non riesco a capire perchè, uso delle LinkedBlocingQueue per le code delle richieste e una HashMap per gli impiegati, uso this.clienti per sincronizzare i due thread che è una variabili Condition di accessoVar.
Se non sono stato molto chiaro domandate pure......

codice:
// metodo chiamato dal cliente per mettersi in coda e svegliare un impiegato
    public boolean richiediServizio(Cliente c, int servizio) throws InterruptedException {
        boolean toRet = false;
        // acquisisco il lock
        this.accessoVar.lock();
        try{
            toRet = true;
                this.clientiAttesa++;
                this.svegliaImpiegato();
                switch (servizio)
                {
                    case 0:
                    {
                        this.contatoreB++;
                        this.println("Inserisco "+c.getName()+" nella coda B");
                        this.tempoB -= System.currentTimeMillis();
                        this.codaB.put(c);
                        this.clienti.signal(); // sveglio un impiegato
                        break;
                    }
                    case 1:
                    {
                        this.contatoreE++;
                        this.println("Inserisco "+c.getName()+" nella coda E");
                        this.tempoE -= System.currentTimeMillis();
                        this.codaE.put(c);
                        this.clienti.signal(); // sveglio un impiegato
                        break;
                    }
                    case 2:
                    {
                        this.contatoreA++;
                        this.println("Inserisco "+c.getName()+" nella coda A");
                        this.tempoA -= System.currentTimeMillis();
                        this.codaA.put(c);
                        this.clienti.signal(); // sveglio un impiegato
                        break;
                    }
                    case 3:
                    {
                        this.contatoreP++;
                        this.println("Inserisco "+c.getName()+" nella coda P");
                        this.tempoP -= System.currentTimeMillis();
                        this.codaP.put(c);
                        this.clienti.signal(); // sveglio un impiegato
                        break;
                    }
            }
        }finally {
            this.accessoVar.unlock();
            return toRet;
        }
    }

    // metodo per svegliare un impiegato per servire un cliente in attesa
    private void svegliaImpiegato() throws InterruptedException {
        Impiegato daSvegliare = null;

        // acquisisco il lock
        this.accessoVar.lock();
        try{
            if(!this.codaImpiegati.isEmpty()){
                Set tmpImpiegato = this.codaImpiegati.keySet();
                Iterator<Impiegato> i = tmpImpiegato.iterator();
                daSvegliare = i.next();
                this.codaImpiegati.get(daSvegliare).signal();
                this.codaImpiegati.remove(daSvegliare);
                this.println("Svegliato "+daSvegliare.getName());
                this.serviCliente(daSvegliare);
            }
        }finally {
            this.accessoVar.unlock();
        }
    }

    // metodo chiamato dall'impiegato: se ci sono clienti li servi altrimenti sospende la sua esecuzione
    public void serviCliente(Impiegato imp) throws InterruptedException {
        // acqusisco il lock
        this.accessoVar.lock();
        try{
            if(this.clientiAttesa == 0) { // nessun cliente in attesa
                this.println("Nessun cliente in attesa, metto in coda "+imp.getName());
                this.codaImpiegati.put(imp, this.accessoVar.newCondition());
                this.codaImpiegati.get(imp).await();
                while(this.clientiAttesa == 0)
                    this.clienti.await();
            }else{
                //seleziono il cliente in attesa da servire
                this.selezionaCliente(imp);
            }
        }finally {
            this.accessoVar.unlock();
        }
    }

    // metodo per selezionare il cliente in attesa da servire in base alla politica di scheduling evitando la starvation
    private void selezionaCliente(Impiegato imp) throws InterruptedException {
        Cliente daServire = null;
        // acquisisco il lock
        this.accessoVar.lock();
        try{
            if((this.codaB.size() > 0) && this.contatore0 < 4) { // dopo 4 richieste B servo una richiesta E
                this.contatore3 = 0;
                this.contatore0++;
                daServire = this.codaB.take();
                this.tempoB += System.currentTimeMillis();
                Thread.sleep(50);
                this.println(imp.getName()+" serve "+daServire.getName()+" con richiesta B");
                this.clientiAttesa--;
            }else {
                if((this.codaE.size() > 0) && this.contatore1 < 3) { // dopo 3 richieste E servo una richiesta A
                    this.contatore1++;
                    daServire = this.codaE.take();
                    this.tempoE += System.currentTimeMillis();
                    Thread.sleep(50);
                    this.println(imp.getName()+" serve "+daServire.getName()+" con richiesta E");
                    this.clientiAttesa--;
                }else {
                    if((this.codaA.size() > 0) && this.contatore2 < 2) { // dopo 2 richieste A servo una richiesta P
                        this.contatore2++;
                        daServire = this.codaA.take();
                        this.tempoA += System.currentTimeMillis();
                        Thread.sleep(50);
                        this.println(imp.getName()+" serve "+daServire.getName()+" con richiesta A");
                        this.clientiAttesa--;
                    }else {
                        if((this.codaP.size() > 0) && this.contatore3 < 1) { // dopo 1 richiesta P servo le richieste B
                            this.contatore0 = 0;
                            this.contatore1 = 0;
                            this.contatore2 = 0;
                            this.contatore3++;
                            daServire = this.codaP.take();
                            this.tempoP += System.currentTimeMillis();
                            Thread.sleep(50);
                            this.println(imp.getName()+" serve "+daServire.getName()+" con richiesta P");
                            this.clientiAttesa--;
                        }else {
                            this.contatore0 = 0;
                            this.contatore1 = 0;
                            this.contatore2 = 0;
                            this.contatore3 = 0;
                        } // END if3
                    } // END if2
                } // END if1
            } // END if0
        }finally {
            this.accessoVar.unlock();
        }
    }
}
EDIT: ecco il progetto così qualcuno magari mi aiuta....
codice:
https://docs.google.com/leaf?id=0BzpNxj_qnZgdNGIyY2EzMjctOGZlZC00MWFjLTg2MzQtZWVhMjc2NjRjMzBm&hl=en_US