Pregunta

Estoy tratando de aprender la esencia básica de un Semáforo en el problema del Filósofo Comedor. En este momento, tengo una variedad de Chopstick de clase, y cada Chopstick tiene un semáforo con 1 permiso disponible:

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 variable de titular se usa para una función que no estoy seguro de necesitar:

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

El programa compila y ejecuta, pero parece tener algunos problemas para liberar los palillos. A veces, los palillos se lanzan, a veces no. Cuando no se lanzan, el programa finalmente se cuelga cuando se toman todos los palillos y un filósofo tiene hambre.

Aquí está el código dentro de la clase Filósofo para liberar el palillo después de un período de tiempo aleatorio:

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");

Mi programa hace salir "Philosopher 0 ha terminado de comerse", por ejemplo, y continúa la ejecución. Las otras dos líneas nunca salen, por lo que obviamente algo está mal con la forma en que estoy liberando.

Cualquier ayuda es apreciada.

¿Fue útil?

Solución

Quitaría la palabra clave 'sincronizada' de las firmas de su método. Está utilizando un mecanismo de bloqueo externo (el semáforo, en este caso). La palabra clave 'sincronizada' está tratando de obtener bloqueos utilizando la exclusión mutua del objeto. Ahora está bloqueando 2 recursos que sospecho podrían estar causando un interbloqueo.

Otros consejos

El problema es que cuando el subproceso 1 tiene un palillo específico y otro intenta obtener el mismo, esperará en el take () -method en la línea this.lock.acquire () ; pero NO liberará el monitor en el objeto en sí.

Si ahora el subproceso 1 intenta liberar el palillo, no puede ingresar al método release () ya que todavía está bloqueado por el otro subproceso que espera en take () . Eso es un punto muerto

Parece un poco confuso que ambos estén bloqueando el palillo y que tenga un semáforo de tamaño 1. En general, un semáforo proporciona tickets para un recurso y, si tiene un solo ticket, eso es efectivamente una exclusión mutua que es idéntica a un bloqueo (ya sea un bloque sincronizado o un objeto de bloqueo). Podría considerar realmente hacer que el Chopstick sea el objeto de bloqueo en sí mismo.

Hice una publicación de blog sobre los filósofos gastronómicos en Java hace un tiempo, si está interesado, aunque en realidad se trata de cómo evitar el punto muerto mediante el uso de otras estrategias.

Asegúrese de que no haya ningún bloqueo o palabra clave sincronizada utilizada. El código a continuación para el chop stick funciona bien para mí ... No soy un profesional, pero debo darte una 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 necesita obtener un bloqueo en ambos chosticks antes de comenzar a comer y primero recogerá el botón izquierdo y luego esperará a la derecha, así que comience a comer, así el método de inicio debe estar sincronizado. Los siguientes métodos lo harán funcionar:

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

public void finishEating(int id) {
    leftChopstick.release();
    rightChopstick.release();
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top