texto
Ao programar em um ambiente simultâneo, é necessário um mecanismo de bloqueio para sincronizar operações entre vários threads para garantir acesso mutuamente exclusivo a recursos compartilhados. O bloqueio pode causar danos ao desempenho, o que parece ser bem conhecido. No entanto, o travamento em si não traz muito consumo de desempenho, e o desempenho é principalmente o processo de aquisição de bloqueios em threads. Se houver apenas um thread competindo por bloqueios e não houver concorrência com vários threads no momento, a JVM otimizará e o consumo de desempenho causado pelo travamento poderá basicamente ser ignorado. Portanto, padronizando a operação do bloqueio, otimizando o método de uso de bloqueio e evitar a concorrência desnecessária de threads, pode não apenas melhorar o desempenho do programa, mas também evitar a possibilidade de encretamento causado por bloqueio irregular e melhorar a robustez do programa. A seguir, explica várias idéias de otimização de bloqueio.
1. Tente não bloquear o método
Quando um bloqueio é adicionado a uma função de membro normal, o encadeamento obtém a trava do objeto do objeto em que o método está localizado. Neste momento, todo o objeto será bloqueado. Isso também significa que, se os métodos de sincronização múltiplos fornecidos por esse objeto forem para diferentes serviços, como todo o objeto estiver bloqueado, quando uma empresa é processada, outros threads de negócios não relacionados também devem esperar. O exemplo a seguir mostra o seguinte:
A classe LockMethod contém dois métodos de sincronização, que são chamados em dois processos de negócios:
classe pública LockMethod {public sincronizado void Busia () {for (int i = 0; i <10000; i ++) {System.out.println (thread.currentThread (). getName ()+"lide com os negócios a:"+i); }} public sincronizado void Busib () {for (int i = 0; i <10000; i ++) {System.out.println (thread.currentThread (). getName ()+"lide com os negócios B:"+i); }}}Bussa é uma aula de threads usada para lidar com um negócio e chama o método Busia () de LockMethod:
classe pública Bussb estende o thread {LockMethod LockMethod; OFEREÇO VOID (LOCKMETHOD LOCKMETHOD) {this.lockMethod = LockMethod; } @Override public void run () {super.run (); LockMethod.busib (); }}TestlockMethod Class usa Thread Bussa e Bussb para processamento de negócios:
classe pública testlockMethod estende thread {public static void main (string [] args) {LockMethod LockMethod = new LockMethod (); BUSSA BUSSA = new Bussa (); Bussb BUSSB = new Bussb (); BUSSA.DEAL (LOCKMETHOD); BUSSB.DEAL (LOCKMETHOD); bussa.start (); bussb.start (); }}Ao executar o programa, você pode ver que, durante a execução do Thread Bussa, o BUSSB não pode inserir o Bussib () da função, porque o bloqueio do objeto de bloqueio é obtido pelo Thread Bussa.
2. Reduza o bloco de código síncrono e bloqueie apenas os dados
Às vezes, para programar a conveniência, algumas pessoas sincronizavam um grande pedaço de código. Se algumas operações neste bloco de código não estiverem relacionadas a recursos compartilhados, eles devem ser colocados fora do bloco síncrono para evitar manter bloqueios por um longo tempo, fazendo com que outros threads permaneçam em um estado de espera. Especialmente algumas operações de ciclo e operações de E/S síncronas. Não apenas significa reduzir o bloco de sincronização na faixa de linha do código, mas também na lógica de execução, o bloco de sincronização deve ser reduzido. Por exemplo, adicione julgamentos mais condicionais e sincronize se atender às condições, em vez de realizar julgamentos condicionais após a sincronização, de modo a minimizar a lógica desnecessária que entra no bloco de sincronização.
3. Tente não incluir bloqueios na fechadura
Essa situação geralmente ocorre. Depois que o encadeamento obtém o bloqueio A, ele chama o método de sincronização de outro objeto no bloqueio do método de sincronização e obtém o segundo bloqueio. Isso pode levar a várias solicitações de bloqueio em uma pilha de chamadas. No caso de multi-threading, pode causar muito complexo e difícil analisar exceções, resultando em impasse. O código a seguir mostra o seguinte:
sincronizado (a) {sincronizado (b) {}}Ou o método de sincronização é chamado no bloco de sincronização:
sincronizado (a) {b b = objarrayList.get (0); B.Method (); // Este é um método de sincronização}A solução é pular e adicionar bloqueios e não incluir bloqueios:
{B b = null; sincronizado (a) {b = objarrayList.get (0); } B.Method ();} 4. Privatize a fechadura e gerencia a fechadura internamente
É mais seguro usar a trava como um objeto privado e não pode ser obtido de fora. Um objeto pode ser bloqueado diretamente por outros threads, e o thread segura a trava do objeto do objeto, por exemplo:
classe a {public void method1 () {}} classe b {public void method1 () {a a = new a (); sincronizado (a) {// bloqueia diretamente a.method1 (); }}}Nesse modo de uso, o bloqueio do objeto do objeto A é mantido por fora, por isso é mais perigoso deixar a trava ser usada em vários lugares fora, e também faz com que problemas leiam o fluxo lógico do código. Uma maneira melhor é gerenciar as fechaduras dentro da classe e fornecer operações de sincronização por meio de interfaces quando o esquema síncrono externo é necessário:
classe A {Private Object Lock = new Object (); public void Method1 () {Synchronized (Lock) {}}} classe B {public void method1 () {a a = novo a (); a.method1 (); }} 5. Realize a decomposição de bloqueio apropriada
Considere o seguinte procedimento:
public class GameServer {public map <string, list <player>> tabelas = novo hashmap <string, list <player>> (); public void ingress (player player, tabela tabela) {if (player.getAccountBalance ()> tabela.getlimit ()) {synchronized (tabelas) {list <player> tabelaPlayers = Tables.get (table.getId ()); if (TablePlayers.size () <9) {TablePlayers.add (Player); }}}}} public void Leave (jogador de jogador, tabela de tabela) {/*omit*/} public void createTable () {/*omit*/} public void DestroTable (tabela Tabela) {/*omit*/}}Neste exemplo, o método de junção utiliza apenas um bloqueio de sincronização para obter o objeto <player> da lista nas tabelas e, em seguida, determine se o número de jogadores é menor que 9. Nesse caso, adicione um jogador. Quando houver milhares de listas <jogador> em tabelas, a competição por travas de tabelas será muito feroz. Aqui, podemos considerar a decomposição do bloqueio: depois de buscar rapidamente os dados, bloqueie o objeto da lista <Player>, para que outros threads possam competir rapidamente para obter o bloqueio do objeto de tabelas:
classe pública GameServer {
mapa público <string,
List <Pomer>> Tables = new Hashmap <String,
Lista <Player>> ();
public void ingress
if (player.getAccountBalance ()> tabela.getLimit ()) {
Lista <Pomer> Tableplayers = null;
sincronizado (tabelas) {
TablePlayers = Tables.get (tabela.getId ());
}
Sincronizado (TablePlayers) {
if (TablePlayers.size () <9) {
TablePlayers.add (jogador);
}
}
}
}
Public Void Leave (jogador, tabela de tabela) {
/*Omitido*/
}
public void createTable () {
/*Omitido*/
}
public void DestroyTable (Tabela Tabela) {
/*Omitido*/
}
}