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 seu código, é possível utilizar o Diagrama de Seqüência UML2 (as visualizações Interações de Objeto e Interações de Encadeamento) e
a Call Stack View (Visualização Pilha de Chamada), além da Thread View (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, localizar o primeiro encadeamento philo* que entrar em um estado "Deadlock (Conflito)". Pause o cursor
sobre o segmento "Deadlock (Conflito)". A dica de ferramentas indica o bloqueio
(Fork.<id number>) e o encadeamento de bloqueio (Locking Thread.<name>), por exemplo:
Lock: Fork 10038
Locking Thread: philo#1
- Clique com o botão direito do mouse no recurso Profiling (Traçado de Perfil) para a execução e selecione Open With (Abrir com) > UML2 Object Interactions (Interações de Objeto UML2). A visualização Diagrama de Seqüência UML2 é aberta, exibindo as Interações
do Objeto.
- No diagrama de seqüência, navegue na visualização horizontalmente para localizar Fork.<id number> e clique para selecioná-lo.

- 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.

- Clique 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 ver que o pedido obteve êxito, pois o encadeamento philo* que está fazendo o
pedido ainda não está no estado "Waiting for Lock (Aguardando Bloqueio)" ou "Deadlock (Conflito)".

- No diagrama de seqüência, clique em Fork.<id number> novamente e role para baixo para localizar o pedido getName que se originou em um encadeamento philo* diferente.
- Clique nessa instância do getName. O indicador Tempo Atual mostrará que o encadeamento philo* fazendo o pedido não obtém o Fork.<id number> e
entra em um estado "Waiting for Lock (Aguardando Bloqueio)"
e, em seguida, "Deadlock (Conflito)".
Nessa instância, um pedido por uma Bifurcação que está sendo suspensa por outro encadeamento é o problema. Verifique outros encadeamentos em conflito para ver se isso é verdadeiro 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 Profiling (Traçado de Perfil) e selecione Open With (Abrir com) > UML2 Thread Interactions (Interações de Encadeamento UML2). A visualização Diagrama de Seqüência UML2 é aberta, exibindo as Interações
do Encadeamento.
- Na visualização Encadeamento, clique no botão drop-down do menu e clique em Open Call Stack View (Abrir Visualização Pilha de Chamada).
- Na visualização Encadeamento, em que os nomes dos encadeamentos são exibidos, dê um clique duplo no primeiro
dos encadeamentos philo* em conflito. Note que a visualização Interações do Encadeamento é alterada para exibir informações apenas para esse encadeamento.
- Role para baixo até o final da informação do encadeamento e dê um clique duplo no último método que o encadeamento executou: o método run. A Call Stack View (Visualização Pilha de Chamada) exibe todas as chamadas na pilha naquele momento.
- Em Pilha de Chamada, note que o encadeamento que está mantendo o bloqueio chamou o método Sleep no Philosopher.java; ou que ele
também está em conflito e, conseqüentemente, não está funcionando.
- Verifique os outros encadeamentos que finalizam a execução em um estado conflitante; o método Sleep no Philosopher.java está normalmente na Pilha de Chamada 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 Open source (Abrir origem). A origem é aberta no editor no local da classe Sleep.
- Examine o código. Note que o método Sleep é chamado pelo 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 File (Arquivo) > Save (Salvar).
Agora crie o perfil do programa novamente.
Nesse momento, ele é executado sem um conflito e gravado 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 este tutorial revisando os materiais no Resumo.