1
resposta

Por que o banheiro continua sendo acessado mesmo com o codigo dentro do synchronized

pessoal, fiz tudo certinho na s aulas, mas parece que temmomentos que a pessoa entra no banheiro antes da limpeza sair . Alguem tem nocao do por que?

ex de output: Jonas is kncking Ezequiel is kncking Limpeza is kncking Jonas Entrando no banheiro Jonas eca, banheiro sujo Limpeza Entrando no banheiro Limpeza limpando o banheiro Ezequiel Entrando no banheiro Ezequiel coisa devagar Ezequiel Descarga Ezequiel Lavando a mao Ezequiel Saindo do banheiro Limpeza Saindo do banheiro Jonas coisa rapida Jonas Descarga Jonas Lavando a mao Jonas Saindo do banheiro

Codigo do banheiro

package br.com.alura.banheiro;

public class Bathroom {

    private boolean isDirty = true;
    //private Lock lock = new ReentrantLock();


    public void number1() {
        var gustName = Thread.currentThread().getName();
        System.out.println(gustName + " is kncking");

        synchronized(this) {
        //lock.lock();
            System.out.println(gustName + " Entrando no banheiro");
            if(isDirty){
                waitOutside(gustName);

            }
            System.out.println(gustName + " coisa rapida");

            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(gustName + " Descarga");
            System.out.println(gustName + " Lavando a mao");
            System.out.println(gustName + " Saindo do banheiro");
        }

//lock.unlock();
    }

    private void waitOutside(String gustName) {
        System.out.println(gustName + " eca, banheiro sujo");
        try {
            this.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void number2() {
        var gustName = Thread.currentThread().getName();
        System.out.println(gustName + " is kncking");

        synchronized(this) {
            System.out.println(gustName + " Entrando no banheiro");
            if(isDirty){
                waitOutside(gustName);
            }
            System.out.println(gustName + " coisa devagar");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(gustName + " Descarga");
            System.out.println(gustName + " Lavando a mao");
            System.out.println(gustName + " Saindo do banheiro");
        }
    }

    public void clean(){
        var gustName = Thread.currentThread().getName();
        System.out.println(gustName + " is kncking");
        //lock.lock();
        synchronized(this) {
            System.out.println(gustName + " Entrando no banheiro");
            if(!isDirty){
                System.out.println(gustName + " Nao ta sujo, saindo");
                return;
            }
            System.out.println(gustName + " limpando o banheiro");

            this.isDirty = false;
            try {
                this.wait(13000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            this.notifyAll();
            System.out.println(gustName + " Saindo do banheiro");
        }
    }
}
1 resposta

Olá José, tudo bem?

O problema pode ser que ao chamar o método wait() em waitOutside() ou em clean() a thread que está executando o método é suspensa o objeto Bathroom é liberado. Isso significa que outras threads que estão aguardando para acessar o banheiro (ou para limpá-lo) podem obter o objeto e executar seu código. Ou seja, quando uma thread é acordada novamente pelo método notifyAll() (ou notify()), o estado do objeto pode ter mudado, o que pode levar a situações inesperadas, como a impressão "Jonas eca, banheiro sujo" após "Limpeza is kncking". Uma possível solução é mover a lógica de espera para dentro do loop do while dentro do método number1() e number2(), onde a condição é verificada novamente após cada despertar. Isso garante que a thread seja acordada apenas quando a condição for verdadeira (ou seja, o banheiro estiver limpo). Além disso, para evitar a possibilidade de falsos "wake ups", o loop deve ser colocado em um bloco try-catch para capturar a exceção InterruptedException.