Como obter o bloqueio de sincronização baseado em String?
Em algum momento, podemos querer fazer algo com base em uma string, por exemplo: para operações simultâneas de sincronização do mesmo usuário, é mais razoável usar uma string de bloqueio.
Porque apenas no caso da mesma sequência, operações simultâneas não são permitidas. E se bloquearmos diretamente todos eles indiscriminadamente, o desempenho geral cairá drasticamente.
Devido à diversidade de String, parece que os bloqueios de string são naturalmente mais vantajosos que os bloqueios avançados, como bloqueios segmentados.
Como a atribuição de variáveis do tipo String é assim: String a = "hello world."; Geralmente, há uma imagem errada e o objeto String é imutável.
Bem, não vamos elaborar sobre esse assunto, em resumo, "a"! = "A" é possível.
Além disso, no que diz respeito à questão do bloqueio, todos sabemos que só faz sentido bloquear o mesmo objeto. Então, grosso modo, podemos usar bloqueios de string como este:
public void method1() {
String str1 = "a";
synchronized (str1) {
// do sync a things...
}
}
public void method2() {
String str2 = "a";
synchronized (str2) {
// do sync b things...
}
}
À primeira vista, isso é realmente muito conveniente e simples. No entanto, como mencionado anteriormente, "a" pode não ser igual a "a" (esse é o caso mais frequente, apenas variáveis de String com o mesmo valor são iguais quando a String é armazenada no pool constante). 5 perguntas complicadas da entrevista com cordas, recomendo a todos que a leiam.
Portanto, podemos otimizar um pouco:
public void method3() {
String str1 = "a";
synchronized (str1.intern()) {
// do sync a things...
}
}
public void method4() {
String str2 = "a";
synchronized (str2.intern()) {
// do sync b things...
}
}
Parece ser muito conveniente e simples, o princípio é colocar o objeto String no pool constante. Mas haverá uma pergunta: como limpar os dados desses pools constantes?
De qualquer forma, podemos implementar um bloqueio baseado em String?
Deve ser possível! Código diretamente!
Quando estiver em uso, basta passar o lockKey. Existem benefícios?
- Usando o ConcurrentHashMap para obter a aquisição de bloqueios, o desempenho ainda é bom;
- Cada sequência corresponde a um bloqueio, que é excluído após o uso, sem causar problemas de estouro de memória;
- Pode ser usado como uma ferramenta externa, o acesso ao código comercial é conveniente, sem a necessidade de sincronizar toda a seção do código como sincronizado;
- Este artigo quer apenas mostrar a implementação do bloqueio de String, esse bloqueio não é adequado para processamento simultâneo em cenários distribuídos;
Extensão: se você não usar String como um bloqueio, como garantir a segurança do encadeamento em um cenário de simultaneidade com probabilidade pequena sob a premissa de simultaneidade grande?
Sabemos que a eficiência do CAS é relativamente alta, podemos usar classes atômicas para executar operações do CAS.
Por exemplo, adicionamos um campo de status e operamos esse campo para garantir a segurança do encadeamento:
Nos testes reais, o desempenho do CAS é melhor que o desempenho do bloqueio, como o sincronizado.
Obviamente, o número de simultaneidades que estamos alvejando aqui é muito pequeno, apenas queremos garantir a segurança do encadeamento nesse caso raro. Então, está tudo bem.