Exercício 1.4: Resolvendo o Gargalo de Encadeamento
Antes de começar, você deve concluir o Exercício 1.3:
Identificando um gargalo de encadeamento.
Para localizar o conflito no código, é possível utilizar o Diagrama de Seqüência UML2 (as visualizações Interações de Objeto e Interações de Encadeamento) e o recurso de criação de perfis Pilha de Chamadas no Monitor de Criação de Perfis, além da visualização Encadeamento.
Para resolver esse conflito, iremos primeiramente descobrir quais chamadas de métodos e quais objetos estão envolvidos no problema:
- Na visualização Encadeamento, localize o primeiro encadeamento philo* que entra em um estado "Aguardando por Trava". Pause o cursor sobre o segmento "Aguardando por Trava". A dica de ferramenta identifica a trava pela qual o encadeamento está aguardando: Fork.<id number>.
- Clique com o botão direito do mouse no recurso de Criação de Perfil para a execução e selecione Abrir Com >Interações do Objeto UML2. A visualização Diagrama de Seqüência UML2 é aberta, exibindo as Interações
do Objeto.
- No diagrama de seqüência, role a visualização para localizar Fork.<id number> e dê um clique duplo para selecioná-la.
- Role para baixo para localizar uma seta horizontal a partir de um dos encadeamentos philo* para Fork.<id number>. Essas setas mostram interações entre objetos, onde a primeira interação entre esses dois objetos indicará que o encadeamento philo* obteve Fork.<id number>. Você localizará uma seta desse tipo rotulada getName.
- Dê um clique duplo em getName. Na visualização Encadeamento, o indicador vertical de Tempo Atual se move para mostrar o que estava ocorrendo no programa inteiro quando getName foi chamado. É possível verificar que o pedido obteve êxito, pois o encadeamento philo* que está fazendo o pedido não entra no estado "Aguardando por Trava".
- No diagrama de seqüência, dê um clique duplo em Fork.<id number> novamente e role para baixo para localizar um pedido getName que originou um encadeamento philo* diferente.
- Dê um clique duplo nessa instância de getName. O indicador Tempo Atual mostrará que o encadeamento philo* que faz o pedido não obtém Fork.<id number> e entra em um estado "Aguardando por Trava".
Nessa instância, um pedido por uma Bifurcação que está sendo suspensa por outro encadeamento é o problema. Verifique outros encadeamentos que terminam no estado "Aguardando por Trava" para verificar se isso também acontece em outras instâncias.
Agora vamos tentar localizar o método que está causando o problema:
- Clique com o botão direito do mouse no recurso de Criação de Perfil para a execução e selecione Abrir Com > Interações do Encadeamento UML2. A visualização Diagrama de Seqüência UML2 é aberta, exibindo as Interações
do Encadeamento.
- No Monitor de Criação de Perfis, expanda o recurso de Criação de Perfil e, em seguida,
a entrada Análise de Encadeamento e a entrada Pilha de Chamadas.
- Na visualização Encadeamento, onde os nomes dos encadeamentos são exibidos, dê um clique duplo no primeiro dos encadeamentos philo* que entra no estado "Aguardando por Trava". Note que a visualização Interações do Encadeamento é alterada para exibir informações apenas para esse encadeamento.
- Role para baixo até o final das informações do encadeamento e dê um clique duplo no último método executado pelo encadeamento: o método run. A Pilha de Chamadas no Monitor de Criação de Perfis exibe todas as chamadas na pilha nesse momento.
- Na Pilha de Chamadas, note que o encadeamento que está suspendendo a trava chamou o método Sleep em Philosopher.java; ou ainda que esteja aguardando por uma trava e, conseqüentemente, não está fazendo nada.
- Verifique os outros encadeamentos que finalizam a execução aguardando por uma trava; o método Sleep em Philosopher.java está freqüentemente na Pilha de Chamadas e pode ser o problema.
Agora suspeitamos do método Sleep. Vejamos o código:
- Na Pilha de Chamadas, clique com o botão direito do mouse em uma instância de Sleep(int) void [Philosopher.java] e selecione Abrir origem. A origem é aberta no editor e no local da classe Sleep.
- Examine o código. Note que o método Sleep é chamado de dentro do método run. Primeiramente há uma chamada para trace, que imprime a mensagem "got left..." e, em seguida, uma chamada para Sleep. Comentando a chamada para Sleep, possivelmente impediremos o conflito.
- Comente Sleep.
- Selecione Arquivo > Salvar.
Agora crie o perfil do programa novamente.
Desta vez ele é executado sem um conflito e grava no console:
HeadWaiter reports all philosophers have finished dining normally
Como é possível ver, a visualização Encadeamento e as outras visualizações mostram o que ocorre com os encadeamentos à medida que o programa é executado. Você é o responsável em analisar e resolver o conflito, com base em seu conhecimento do programa.
Conclua o tutorial revisando os materiais no Sumário.