Problemas de semáforo em Java com os filósofos de jantar
-
03-07-2019 - |
Pergunta
Estou tentando aprender o jist básico de um semáforo no problema do filósofo para refeições. No momento, tenho uma variedade de pauzinhos de classe e cada pauzinho tem um semáforo com 1 licença disponível:
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;
}
}
A variável do suporte é usada para uma função que não tenho certeza de que preciso:
public synchronized void conditionalRelease()
{
if (holder == Thread.currentThread())
{
holder = null;
this.lock.release();
}
}
O programa compila e executa, mas parece ter alguns problemas para liberar os pauzinhos. Às vezes, os pauzinhos são liberados, às vezes não. Quando eles não se liberam, o programa acaba desligando quando todos os pauzinhos são levados e um filósofo está com fome.
Aqui está o código da classe filósofaria para lançar o pauzinho após um período aleatório de tempo:
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");
Meu programa produz "filósofo 0 terminou de comer", por exemplo, e continua a execução. As outras duas linhas nunca saíram, então, obviamente, algo está errado com a maneira como estou lançando.
Qualquer ajuda é apreciada.
Solução
Eu tiraria a palavra -chave 'sincronizada' das assinaturas de seu método. Você está usando um mecanismo de travamento externo (o semáforo, neste caso). A palavra -chave 'sincronizada' está tentando obter bloqueios usando o próprio mutex do objeto. Agora você está bloqueando 2 recursos que eu suspeito que possam estar causando um impasse.
Outras dicas
O problema é que, quando o thread1 tem um pauzinho específico e outro tenta obter o mesmo, ele vai esperar no take()
-Metódico on -line this.lock.acquire();
mas vai NÃO Libere o monitor no próprio objeto.
Se agora Thread1 tenta liberar o pauzinho, ele não pode entrar no release()
-Metódico, já que ainda está bloqueado pelo outro tópico esperando em take()
. Isso é um impasse
Parece um pouco confuso que vocês dois estão bloqueando o pauzinho e mantê -lo um semáforo do tamanho 1. Geralmente, um semáforo fornece ingressos para um recurso e, se você tiver apenas um ingresso, isso é efetivamente exclusão mútua, idêntica a uma trava ( um bloco sincronizado ou um objeto de bloqueio). Você pode considerar realmente fazer do pauzinho o próprio objeto de trava.
Fiz uma postagem no blog sobre os filósofos de jantar em Java há algum tempo, se você estiver interessado, embora seja realmente sobre como evitar o impasse usando outras estratégias.
Verifique se não há nenhuma palavra -chave de bloqueio ou sincronizado usado. O código abaixo para o chop stick funciona bem para mim .. não é um profissional, mas deve te dar uma ideia;
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){}
}
}
O Filosffer precisa adquirir o bloqueio em ambos os Chosticks antes de começar a comer e pegará o Leforne primeiro e aguarde a direita, então comece a comer, para que o método de início deve ser sincronizado. Os métodos a seguir farão com que funcione:
public synchronized void startEating() {
leftChopstick.acquire();
rightChopstick.acquire();
}
public void finishEating(int id) {
leftChopstick.release();
rightChopstick.release();
}