2009-03-03 33 views
5

Estoy tratando de aprender el jist básico de un semáforo en el problema del filósofo gastronómico. En este momento, tengo una serie de palillos de clase, y cada Palillo tiene un semáforo con 1 permiso disponibles:Problemas de semáforo en Java con los filósofos del comedor

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 soporte, utilice una función que no estoy seguro de que necesito:

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

El programa se compila y se ejecuta, pero parece tener algunos problemas para liberar los palillos. A veces, los palillos se liberan, a veces no lo hacen. Cuando no se liberan, el programa finalmente cuelga cuando se toman todos los palillos y un filósofo está hambriento.

Este es el código dentro de la clase Filósofo para liberar el palillo después de un periodo 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 lo hace la salida "0 Filósofo ha terminado de comer", por ejemplo, y continúa la ejecución. Las otras dos líneas nunca salen, entonces obviamente algo está mal con la forma en que estoy liberando.

Cualquier ayuda es apreciada.

Respuesta

8

Quitaría la palabra clave 'sincronizada' de sus firmas de métodos. Está utilizando un mecanismo de bloqueo externo (el semáforo, en este caso). La palabra clave 'sincronizada' está tratando de obtener bloqueos utilizando el propio mutex del objeto. Ahora está bloqueando 2 recursos que sospecho que pueden estar causando un punto muerto.

+0

Ja! Eso es exactamente lo que era ... tuve que implementar estas dos formas diferentes para una tarea y copié el código pegado para el primer método y olvidé eliminar la palabra clave sincronizada. Buen hallazgo –

1

El problema es que cuando Thread1 tiene un palillo específico y otros intentos para conseguir la misma se va a esperar en el take() -method en la línea this.lock.acquire(); pero será NO liberar el monitor en el objeto mismo.

Si ahora thread1 intenta liberar el palillo, no puede ingresar el release() -metodo porque todavía está bloqueado por el otro subproceso que espera en take(). Eso es un punto muerto

1

Parece un poco confuso que ambos estén bloqueando el palillo y haciendo que sostenga un semáforo de tamaño 1. Generalmente un semáforo proporciona boletos para un recurso y si solo tiene un boleto, eso es efectivamente exclusión mutua que es idéntico a un bloqueo (ya sea un bloque sincronizado o un objeto Lock). Podría considerar hacer del Chopstick el objeto de bloqueo en sí mismo.

Hace un tiempo publiqué un blog sobre los filósofos del comedor en Java si te interesa, aunque se trata de cómo evitar el estancamiento mediante el uso de otras estrategias.

+0

Parece que esto era parte de una tarea de tarea en la que tenía algún requisito de cooky que indicaba que tenía que usar semáforos. –

+0

La otra cosa que puedes hacer es tener Chopstick extendiendo Semaphore (o Lock). :) Aunque eso no le comprará nada sobre usarlo directamente. –

0

Filósofo necesita adquirir bloqueo en ambos chosticks antes de comer iniciará y leftone recogida primero y luego esperar a la derecha para comenzar a comer así que empieza método debe ser sincronizado. siguientes métodos harán que funcione:

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

public void finishEating(int id) { 
    leftChopstick.release(); 
    rightChopstick.release(); 
} 
1

Asegúrese de que no hay ningún bloqueo o palabra clave utilizada sincronizada. El código a continuación para chop stick funciona bien para mí ..No es profesional, pero debe darle alguna 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){} 
} 

}

Cuestiones relacionadas