Um ReentrantLock não é estruturado , diferentemente das synchronized
construções - ou seja, você não precisa usar uma estrutura de bloco para bloquear e pode até manter um bloqueio entre os métodos. Um exemplo:
private ReentrantLock lock;
public void foo() {
...
lock.lock();
...
}
public void bar() {
...
lock.unlock();
...
}
É impossível representar esse fluxo através de um único monitor em uma synchronized
construção.
Além disso, ReentrantLock
suporta pesquisa de bloqueio e espera de bloqueio interrompível que suportam tempo limite . ReentrantLock
também oferece suporte à política de justiça configurável , permitindo um agendamento de encadeamento mais flexível.
O construtor para esta classe aceita um parâmetro de justiça opcional . Quando definido true
, sob contenção, os bloqueios favorecem a concessão de acesso ao segmento de espera mais longa. Caso contrário, esse bloqueio não garante nenhuma ordem de acesso específica. Os programas que usam bloqueios justos acessados por muitos encadeamentos podem exibir uma taxa de transferência geral mais baixa (ou seja, são mais lentos; geralmente muito mais lentos) do que aqueles que usam a configuração padrão, mas apresentam variações menores no tempo para obter bloqueios e garantir falta de fome. Observe, no entanto, que a justiça dos bloqueios não garante a justiça do agendamento de encadeamentos. Portanto, um dos muitos encadeamentos que usam um bloqueio justo pode obtê-lo várias vezes seguidas, enquanto outros encadeamentos ativos não estão progredindo e atualmente não estão mantendo o bloqueio. Observe também que o tempo limitetryLock
O método não respeita a definição de justiça. Será bem-sucedido se o bloqueio estiver disponível, mesmo se outros threads estiverem aguardando.
ReentrantLock
também pode ser mais escalável , com desempenho muito melhor em contenções mais altas. Você pode ler mais sobre isso aqui .
Esta alegação foi contestada, no entanto; veja o seguinte comentário:
No teste de bloqueio reentrante, um novo bloqueio é criado a cada vez, portanto, não há bloqueio exclusivo e os dados resultantes são inválidos. Além disso, o link da IBM não oferece código-fonte para o benchmark subjacente, portanto, é impossível caracterizar se o teste foi realizado corretamente.
Quando você deve usar ReentrantLock
s? De acordo com o artigo do developerWorks ...
A resposta é bastante simples - use-a quando você realmente precisar de algo que synchronized
não seja fornecido , como esperas temporizadas de bloqueio, esperas de interrupção interrompíveis, bloqueios não estruturados em bloco, várias variáveis de condição ou pesquisa de bloqueios. ReentrantLock
também possui benefícios de escalabilidade, e você deve usá-lo se realmente tiver uma situação que contenha alta contenção, mas lembre-se de que a grande maioria dos synchronized
blocos quase nunca exibe qualquer contenção, muito menos alta contenção. Eu recomendaria o desenvolvimento com sincronização até que a sincronização se mostre inadequada, em vez de simplesmente assumir que "o desempenho será melhor" se você usarReentrantLock
. Lembre-se, essas são ferramentas avançadas para usuários avançados. (E usuários verdadeiramente avançados tendem a preferir as ferramentas mais simples que podem encontrar até se convencerem de que as ferramentas simples são inadequadas.) Como sempre, faça as coisas primeiro e depois se preocupe se você precisa ou não fazê-las mais rapidamente.