Antes do Java 5.0, havia apenas bloqueios sincronizados (bloqueios integrados) e voláteis. Após o Java 5.0, o bloqueio de exibição ReentrantLock foi introduzido.
Visão geral do ReentrantLock
ReentrantLock é um bloqueio reentrante. É diferente do bloqueio integrado. Ele requer bloqueio e desbloqueio explícitos sempre que é usado e fornece recursos mais avançados: bloqueio justo, bloqueio cronometrado, bloqueio condicional e bloqueio pollable. o bloqueio. Ele pode efetivamente evitar o problema de atividade do impasse.
Interface de bloqueio:
Copie o código do código da seguinte forma:
bloqueio de interface pública {
//Bloqueia até que o bloqueio seja obtido ou interrompido
bloqueio vazio();
//Bloqueia até que o bloqueio seja obtido ou uma exceção seja lançada ao interromper
void lockInterruptably() lança InterruptedException;
//Obtém apenas quando o bloqueio está disponível, caso contrário retorna diretamente
booleano tryLock();
//Obtém o bloqueio apenas se ele estiver disponível dentro do tempo especificado, caso contrário, retorna diretamente e lança uma exceção quando interrompido
boolean tryLock (tempo longo, unidade TimeUnit) lança InterruptedException;
void desbloquear();
//Retorna uma condição vinculada a este bloqueio
Condição novaCondição();
}
Uso de bloqueio
Copie o código do código da seguinte forma:
Bloqueio de bloqueio = new ReentrantLock();
bloqueio.lock();
tentar{
//atualiza o status do objeto
}finalmente{
//Observe aqui que deve haver um bloco de código finalmente para desbloquear
//Caso contrário, é fácil causar impasses e outros problemas de atividade.
bloquear.desbloquear();
}
Recursos do ReentrantLock
Bloqueios de votação e bloqueios cronometrados
Solicitações de bloqueio pesquisáveis e cronometradas são implementadas por meio do método tryLock(), que é diferente da aquisição incondicional de bloqueios. ReentrantLock pode ter um mecanismo flexível de tolerância a falhas. Muitos casos de deadlock são causados por bloqueios sequenciais e diferentes threads estão tentando adquirir. locks.Ele bloqueia ao bloquear e não libera o bloqueio que já possui, eventualmente causando um deadlock. Quando o método tryLock() tenta obter um bloqueio, se o bloqueio já estiver mantido por outro thread, ele retornará imediatamente de acordo com o método de configuração, em vez de bloquear e esperar. retornando Você pode devolvê-lo de acordo com o retorno. Como resultado, tente novamente ou cancele para evitar conflito.
justiça
O construtor ReentrantLock oferece duas opções: bloqueio justo e bloqueio injusto (padrão). Chamados de bloqueios justos, os threads adquirirão bloqueios na ordem em que emitem solicitações, e o salto de fila não é permitido, mas para bloqueios injustos, o salto de fila é permitido: quando um thread solicita a aquisição de um bloqueio, se o bloqueio estiver disponível; , então este thread irá ignorar o thread em espera na fila e adquirir o bloqueio. Geralmente queremos que todos os bloqueios sejam injustos. Porque ao realizar operações de bloqueio, a imparcialidade reduzirá bastante o desempenho devido à sobrecarga de suspensão e recuperação de thread. Considere uma situação: o thread A mantém um bloqueio, o thread B solicita o bloqueio, então o thread B é suspenso quando o thread A libera o bloqueio, o thread B será despertado e tentará adquirir o bloqueio ao mesmo tempo; C também solicita a aquisição desse bloqueio, então o thread C provavelmente adquirirá, usará e liberará esse bloqueio antes que o thread B seja totalmente despertado. Esta é uma situação em que todos ganham. O momento em que B adquire o bloqueio (B pode adquiri-lo somente depois de acordar) não é atrasado e o rendimento também é melhorado. Na maioria dos casos, o desempenho dos bloqueios injustos é superior ao desempenho dos bloqueios justos.
As operações de aquisição de bloqueio podem ser interrompidas
O método lockInterruptably adquire o bloqueio enquanto permanece responsivo às interrupções, portanto não há necessidade de criar outros tipos de operações de bloqueio ininterruptas.
ReadWriteLockReadWriteLock
ReentrantLock é um bloqueio mutex padrão. Apenas um thread pode manter o bloqueio por vez. O bloqueio de leitura e gravação é diferente. Ele expõe dois objetos Lock, um dos quais é usado para operações de leitura e o outro para operações de gravação.
Copie o código do código da seguinte forma:
interface pública ReadWriteLock {
/**
* Retorna o cadeado utilizado para leitura.
*
* @return o cadeado utilizado para leitura.
*/
Bloquear readLock();
/**
* Retorna o cadeado utilizado para escrita.
*
* @return o cadeado usado para escrita.
*/
Bloquear writeLock();
}
Implementação opcional:
1. Prioridade de lançamento
2. Leia os saltos de linha na linha
3. Reentrada
4. Rebaixar
5.Atualizar
ReentrantReadWriteLock implementa a interface ReadWriteLock e o construtor fornece dois métodos de criação: bloqueio justo e bloqueio injusto. Os bloqueios de leitura e gravação são adequados para situações em que há mais leitura e menos escrita e podem obter melhor simultaneidade.
O código de cópia de exemplo é o seguinte:
classe pública ReadWriteMap<K, V> {
mapa privado<K, V> mapa;
bloqueio ReadWriteLock final privado = new ReentrantReadWriteLock();
bloqueio final privado readLock = lock.readLock();
bloqueio final privado writeLock = lock.writeLock();
public ReadWriteMap(Mapa<K, V> mapa) {
este.map = mapa;
}
público V get(chave K) {
readLock.lock();
tentar {
retornar mapa.get(chave);
} finalmente {
readLock.unlock();
}
}
public void put(chave K, valor V) {
writeLock.lock();
tentar {
map.put(chave, valor);
} finalmente {
writeLock.unlock();
}
}
}