Crie threads ``barbeiro'' e threads ``cliente''. A vida de um cliente é muito monótona: ele vai até a barbearia para cortar seu cabelo (pode ser que não consiga, caso a barbearia esteja cheia), depois faz outras coisas menos importantes (ou seja, espera um tempo aleatório), depois vai cortar seu cabelo novamente. A vida de um barbeiro também é monótona: ele pega um cliente, corta o cabelo dele (ou seja, espera um tempo aleatório), avisa esse cliente que o corte acabou e passa para o próximo cliente.
A saída do seu programa deve indicar que barbeiro está atendendo a que cliente (ou seja, o programa associa uma identificador a cada barbeiro e a cada cliente).
Uma das classes do programa deve implementar conceitualmente um monitor que encapsula todos os acessos à barbearia. O ``conceitualmente'' aqui indica que você provavelmente não fará uma tradução direta do monitor em classe Java, com synchronized em todos os métodos públicos, pois isso não é adequado para o caso de múltiplas condições (a menos também se use chamadas notifyAll()). Esse monitor tem os métodos indicados abaixo:
monitor Barbearia { // Campos (variáveis privadas) do monitor ... // Operação chamada pelos clientes: boolean cortaCabelo() { ... } // se a barbearia não estiver lotada, espera // que o corte seja feito e retorna true // se a barbearia estiver lotada, retorna false // Operações chamadas pelos barbeiros: void proximoCliente() { ... } // pega o próximo cliente (dentro desta chamada // o barbeiro pode dormir esperando um cliente) void corteTerminado() { ... } // o barbeiro acorda o cliente que está na sua // cadeira e espera que ele saia da barbearia // (tome cuidado para acordar o cliente certo) }
Se achar conveniente, adicione aos métodos proximoCliente() e corteTerminado() um parâmetro que identifica o barbeiro que atenderá ou atendeu o cliente:
void proximoCliente(int idBarbeiro) { ... } void corteTerminado(int idBarbeiro) { ... }