Aplicação e princípio do readwritelock reentrante

Índice

1. Introdução

2. Aplicação

3. Princípio


1. Introdução

Quando as operações de leitura são muito maiores do que as operações de gravação , use bloqueios de leitura e gravação neste momento para permitir que as leituras sejam simultâneas e melhorem o desempenho

Semelhante ao bloqueio compartilhado, selecione...de...bloqueie no modo de compartilhamento no banco de dados  

Forneça uma classe de contêiner de dados com um método read() que usa um bloqueio de leitura para proteger os dados e um método write() que usa um bloqueio de gravação para proteger os dados

Duas threads read e read não são mutuamente exclusivas, read e write e write e write são mutuamente exclusivas

Precauções:

  • Bloqueios de leitura não suportam variáveis ​​de condição
  • A atualização não é suportada durante a reentrada : Adquirir um bloqueio de gravação enquanto mantém um bloqueio de leitura fará com que a aquisição do bloqueio de gravação aguarde indefinidamente, e o bloqueio de leitura deve ser liberado antes de adquirir o bloqueio de gravação
  • Suporte para downgrade durante a reentrada : manter um bloqueio de gravação pode adquirir um bloqueio de leitura

2. Aplicação

Atualizamos o cache com duas operações

Excluir o cache primeiro: Devemos considerar esse problema quando implementamos o cache e o banco de dados. Por exemplo, quando há uma thread a consultando o banco de dados e se preparando para atualizar os dados do banco de dados para o cache, a thread b altera o banco de dados. Isso às vezes, se o cache for atualizado com sucesso, ele ficará inconsistente com os dados que foram alterados no banco de dados e, portanto, os dados antigos no cache sempre serão usados ​​​​posteriormente.

Atualize o banco de dados primeiro: é melhor atualizar o banco de dados primeiro e a inconsistência do banco de dados do cache será menor, mas para garantir uma consistência forte, os bloqueios ainda são necessários. Porque quando o banco de dados é alterado primeiro e o cache não foi excluído, a consulta neste momento são todos os dados antigos, que são inconsistentes

O bloqueio aqui pode ser otimizado com bloqueios de leitura e gravação

  • Bloqueio de leitura : se houver dados no cache, consulte o cache e lembre-se de liberar o bloqueio de leitura aqui (porque se o cache não precisar ser consultado, um bloqueio de gravação será necessário e você não poderá obter um bloqueio de gravação se mantenha um bloqueio de leitura)
  • Bloqueio de gravação : não há dados no cache, consulte o banco de dados e grave no cache (se muitos threads forem capturar o bloqueio, pode haver muitas filas, mas isso só precisa de uma, portanto, verificações duplas são necessárias)
  • Bloqueio de gravação : atualize, primeiro atualize o banco de dados e depois exclua o cache

Esse tipo de otimização se reflete principalmente na situação em que a leitura e a gravação podem ser compartilhadas em cenários onde são feitas mais leituras e menos gravações. No entanto, se você quiser melhorar ainda mais a simultaneidade, pode dividi-la de maneira mais refinada . E esta situação é adequada apenas para cenários autônomos

3. Princípio

O bloqueio de leitura e gravação usa o mesmo sincronizador de sincronização, portanto, a fila de espera, o estado etc. também são os mesmos

Mas também há uma diferença. Seu estado mudou, porque o status do bloqueio de leitura e do bloqueio de gravação deve ser registrado. Os 16 bits superiores registram o bloqueio de leitura e os 16 bits inferiores registram o bloqueio de gravação . Outros processos são semelhantes ao bloqueio reentrante

Bloqueio de gravação

Não há diferença entre adicionar um bloqueio de gravação e antes. Verifique primeiro o estado. Se o estado for igual a 0, significa que nem o bloqueio de leitura nem o bloqueio de gravação foram adicionados e, em seguida, julgue um método (se o bloqueio injusto retorna falso diretamente, verifique se há um bloqueio justo. Você deve enfileirar e retornar se não o fizer), então cas para bloquear e, se for bem-sucedido, defina o encadeamento de bloqueio atual como exclusiveOwnerThread. Se for considerado que o estado não é 0, o bloqueio de leitura pode ser adicionado ou o bloqueio de gravação é adicionado. Se o bloqueio de leitura for adicionado, ele será mutuamente exclusivo e retornará falso diretamente. Se o add for um bloqueio de gravação, veja se foi adicionado por você mesmo. A única coisa é reinserir o status de bloqueio de gravação + 1. Se for de outra pessoa, retornará falso. Claro, se o número de reentradas exceder um determinado número de vezes , 65535 também lançará uma exceção.

adicionar bloqueio de leitura

Primeiro julgue o estado e, em seguida, verifique se a parte do bloqueio de gravação é 0. Se não for 0 && é a pessoa que adicionou o bloqueio de gravação? Os bloqueios de leitura não podem ser adicionados aos bloqueios de gravação). Se for -1, ele julgará novamente se pode obter o bloqueio de leitura ou, se não puder, entrará na fila de bloqueio e aguardará.

Perceber:

Embora seus encadeamentos bloqueados estejam todos em uma fila de bloqueio, seus estados são diferentes devido aos diferentes bloqueios aos quais eles se aplicam. Aqueles que aguardam um bloqueio de leitura estão no estado compartilhado, aqueles que aguardam um bloqueio de gravação estão no estado ex e o os estados dos nós anteriores são - 1 tem a responsabilidade de acordar os nós seguintes, mas o estado do último nó é 0 , e não há necessidade de acordar depois

liberação de bloqueio de gravação

Reduza diretamente o número de estados em -1 e verifique se é 0. Se não for 0, a reentrada do bloqueio é reduzida em 1 e retorna falso, se for 0 após a redução, retorna verdadeiro. Se retornar true, defina o thread de bloqueio atual como nulo e, em seguida, verifique o nó principal da fila bloqueada.Se houver um estado de corte de gás diferente de 0, ative-o. Depois de acordar, continue a competir pelo bloqueio e descubra que ninguém tem o bloqueio, adicione um bloqueio de gravação ao cas, adicione um bloqueio de alto nível e retorne 1 para indicar que o bloqueio foi bem-sucedido. Então é necessário acordar da fila bloqueada.Se for um bloqueio de leitura, acorde.

Depois de alterar o nó na fila de bloqueio, obtenha o próximo do nó atual. Se o próximo nó for um compartilhado que deseja adicionar um bloqueio de leitura, altere o -1 do nó atual para 0 e, em seguida, desperte o seguinte nós e, em seguida, deixe o status do bloqueio de leitura ser +1 (vários threads podem ler o bloqueio para aumentar a contagem) e, em seguida, exclua este nó na fila bloqueada e altere-o para o próximo e continue a julgar se o o próximo é um nó de leitura, se for uma duplicata.

ler liberação de bloqueio

Obtenha o estado do estado, defina o estado de bloqueio de leitura como -1 e, em seguida, use cas para definir o estado para ver se pode ser bem-sucedido. Após o sucesso, julgue se é 0. Se for verdadeiro, não é 0 ou falso . Se for 0, vá para o nó principal da fila bloqueada.Se o estado do nó principal for -1, ative esse nó e, se não for -1, tente novamente.

Acho que você gosta

Origin blog.csdn.net/weixin_54232666/article/details/131157121
Recomendado
Clasificación