"Olá, amigo! Temos uma panacéia — uma cura para todas as doenças. Como já vimos, a troca descontrolada de threads é um problema."
"Por que os próprios threads não podem decidir quando mudar para o próximo thread? Faça tudo o que eles precisam fazer e então sinalize: «Terminei!»?"
"Permitir que os próprios threads controlem a troca seria um problema ainda maior. Suponha que você tenha um código mal escrito e o thread nunca renuncie à CPU. Antigamente, era assim que funcionava. E era um pesadelo e tanto."
"Tudo bem. Então, qual é a solução?"
" Bloqueando outros tópicos. É assim que funciona."
Ficou claro que as threads interferem umas nas outras quando tentam usar objetos e/ou recursos compartilhados . Assim como vimos no exemplo com a saída do console: há um console e todos os threads são enviados para ele. É bagunçado.
Assim, um objeto especial foi inventado: o mutex . É como uma placa na porta do banheiro que diz «disponível / ocupado» . Ele tem dois estados: o objeto está disponível ou ocupado . Esses estados também são chamados de «bloqueado» e «desbloqueado».
Quando um thread precisa de um objeto compartilhado com outros threads, ele verifica o mutex associado ao objeto. Se o mutex for desbloqueado, o thread o bloqueia (marca-o como «ocupado») e começa a usar o recurso compartilhado. Após o thread ter feito seu trabalho, o mutex é desbloqueado (marcado como «disponível»).
Se o thread quiser usar o objeto e o mutex estiver bloqueado, o thread ficará suspenso enquanto espera. Quando o mutex for finalmente desbloqueado pelo thread de ocupação, nosso thread irá bloqueá-lo imediatamente e começar a executar. A analogia com uma placa de porta de banheiro é perfeita.
"Então, como trabalho com um mutex? Preciso criar objetos especiais?"
"É muito mais simples do que isso. Os criadores de Java criaram esse mutex na classe Object. Portanto, você nem precisa criá-lo. Faz parte de todos os objetos. Veja como tudo funciona:"
Código | Descrição |
---|---|
|
O método swap troca os valores das variáveis name1 e name2.
O que pode acontecer se for chamado de dois threads ao mesmo tempo? |
Execução real do código | Código da primeira thread | Código da segunda thread |
---|---|---|
|
|
|
A linha de fundo |
---|
Os valores das variáveis foram trocados duas vezes, retornando aos seus lugares originais. |
Preste atenção à palavra-chave sincronizado .
"Sim, o que isso significa?"
"Quando um thread entra em um bloco de código marcado como sincronizado, a máquina Java bloqueia imediatamente o mutex do objeto indicado entre parênteses após a palavra sincronizado. Nenhum outro thread pode entrar neste bloco até que nosso thread saia dele. Assim que nosso thread sair o bloco marcado como sincronizado, o mutex é imediata e automaticamente desbloqueado e ficará disponível para ser adquirido por outra thread."
Se o mutex estiver ocupado, nosso thread ficará parado e esperará que ele seja liberado.
"Tão simples e tão elegante. É uma bela solução."
"Sim. Mas o que você acha que vai acontecer neste caso?"
Código | Descrição |
---|---|
|
Os métodos swap e swap2 compartilham o mesmo mutex (o objeto this ). |
O que acontece se uma thread chamar o método swap e outra thread chamar o método swap2?
"Como o mutex é o mesmo, o segundo thread terá que esperar até que o primeiro thread saia do bloco sincronizado. Portanto, não haverá problemas com acesso simultâneo."
"Muito bem, amigo! Essa é a resposta correta!"
Agora eu gostaria de apontar que sincronizado pode ser usado para marcar não apenas blocos de código, mas também métodos. Aqui está o que isso significa:
Código | O que realmente acontece |
---|---|
|
|
GO TO FULL VERSION