Domanda

Sto cercando di imparare il jist di base di un semaforo nel problema del filosofo da pranzo. In questo momento, ho un array di classe Chopstick e ogni Chopstick ha un semaforo con 1 permesso disponibile:

public class Chopstick
{
    Thread holder = null;
    private Semaphore lock = new Semaphore(1);

    public synchronized void take() throws InterruptedException
    {
        this.lock.acquire();
        holder = Thread.currentThread();

    }

    public synchronized void release()
    {   
        this.lock.release();
        holder = null;
    }
}

La variabile holder viene utilizzata per una funzione di cui non sono sicuro di aver bisogno:

public synchronized void conditionalRelease()
{
    if (holder == Thread.currentThread())
    {
        holder = null;
        this.lock.release();
    }
}

Il programma viene compilato ed eseguito, ma sembra avere qualche problema nel rilasciare le bacchette. A volte, le bacchette vengono rilasciate, a volte no. Quando non vengono rilasciati, il programma alla fine si blocca quando vengono prese tutte le bacchette e un filosofo ha fame.

Ecco il codice all'interno della classe Philosopher per rilasciare la bacchette dopo un periodo di tempo casuale:

System.out.println(this.name + " is eating");
Thread.sleep(this.getRandTime());
System.out.println(this.name + " has finished eating");

rightChopstick.release();
System.out.println(this.name + " has released the right chopstick");
leftChopstick.release();
System.out.println(this.name + " has released the left chopstick");

Il mio programma genera " Philosopher 0 ha finito di mangiare " ;, ad esempio, e continua l'esecuzione. Le altre due linee non escono mai, quindi ovviamente qualcosa non va nel modo in cui sto rilasciando.

Qualsiasi aiuto è apprezzato.

È stato utile?

Soluzione

Vorrei togliere la parola chiave "sincronizzata" dalle firme del metodo. Stai utilizzando un meccanismo di blocco esterno (il semaforo, in questo caso). La parola chiave "sincronizzata" sta cercando di ottenere i blocchi utilizzando il mutex proprio dell'oggetto. Ora stai bloccando 2 risorse che sospetto possano causare un deadlock.

Altri suggerimenti

Il problema è che quando thread1 ha un bastoncino specifico e un altro cerca di ottenere lo stesso, attenderà il metodo take () sulla linea this.lock.acquire () ; ma NON rilascerà il monitor sull'oggetto stesso.

Se ora thread1 tenta di rilasciare la bacchette, non può inserire il metodo release () poiché è ancora bloccato dall'altro thread in attesa in take () . È un punto morto

Sembra un po 'confuso il fatto che si stiano entrambi bloccando la bacchette e che sia in possesso di un semaforo di dimensione 1. Generalmente un semaforo fornisce i biglietti per una risorsa e se si dispone di un solo biglietto, si tratta effettivamente di un'esclusione reciproca identica a un blocco (o un blocco sincronizzato o un oggetto Lock). Potresti prendere in considerazione l'idea di rendere l'oggetto Chopstick stesso come oggetto di blocco.

Ho pubblicato un post sul blog sui filosofi della ristorazione a Java qualche tempo fa, se sei interessato, anche se si tratta davvero di come evitare lo stallo usando altre strategie.

Assicurati che non vi siano parole chiave bloccate o sincronizzate utilizzate. Il codice qui sotto per il chop stick funziona bene per me .. Non è un professionista ma devi darti un'idea;

public class Chopstick {
private boolean inuse;
Semaphore sem;

public Chopstick(){

    inuse = false;
    sem = new Semaphore(1);
}
public void pickUp()
{
    try
    {
        while(inuse)
        {
            try
            {
                sem.acquire();

            }
            catch(InterruptedException e) {}
        }
        inuse = true;
    }catch(Exception e){}
}
public void putDown()
{
    try
    {
        inuse = false;
        sem.release();

    }
    catch (Exception e){}
}

}

Philospher deve acquisire il blocco su entrambi i chostick prima di iniziare a mangiare e raccoglierà prima uno a sinistra, quindi aspetta il diritto quindi inizia a mangiare, quindi il metodo di avvio deve essere sincronizzato. I seguenti metodi lo faranno funzionare:

public synchronized void startEating() {
    leftChopstick.acquire();
    rightChopstick.acquire();
}

public void finishEating(int id) {
    leftChopstick.release();
    rightChopstick.release();
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top