Em Java, a palavra-chave sincronizada pode ser usada para o controle de sincronização de threads para obter acesso seqüencial aos principais recursos e evitar a inconsistência de dados causada pela execução simultânea multitreada. O princípio do sincronizado é um monitor de objeto (bloqueio). Somente o thread que adquire o monitor pode continuar sendo executado; caso contrário, o thread aguardará para adquirir o monitor. Cada objeto ou classe em Java tem um bloqueio associado a ele. Para um objeto, ele monitora a variável de instância desse objeto. Para uma classe, ele monitora a variável de classe (uma classe em si é um objeto da classe, portanto, o bloqueio associado à classe também é um bloqueio de objeto). Existem duas maneiras de usar palavras -chave sincronizadas: método sincronizado e bloco sincronizado. Ambas as áreas de monitoramento estão associadas a um objeto introduzido. Quando atingir essa área de monitoramento, a JVM bloqueará o objeto de referência e, quando sair, a trava no objeto de referência será liberada (a JVM liberará o bloqueio quando houver uma exceção de saída). Os bloqueios de objetos são mecanismos internos da JVM. Você só precisa gravar métodos de sincronização ou blocos de sincronização. Ao operar as áreas de monitoramento, a JVM adquirirá ou liberará automaticamente o bloqueio.
Exemplo 1
Vamos primeiro olhar para o primeiro exemplo. Em Java, existe apenas uma área crítica do mesmo objeto que pode ser acessado ao mesmo tempo (todos os métodos sincronizados não estáticos):
pacote concorrência; classe pública main8 {public static void main (string [] args) {conta de conta = new Account (); conta.setBalance (1000); Empresa da empresa = nova empresa (conta); Thread CompanyThread = new Thread (Empresa); Banco bancário = novo banco (conta); Thread BankThread = new Thread (banco); System.out.printf ("Conta: Balance Inicial: %f/n", Account.getBalance ()); Companythread.start (); BankThread.start (); tente {// junção () Método aguarda esses dois threads para concluir a CompanyThread.join (); BankThread.join (); System.out.printf ("Conta: Balanço Final: %f/n", Account.getBalance ()); } catch (interruptedException e) {e.printStackTrace (); }}} /*Conta*/Class Conta {Balance duplo privado; /*Adicione dados de entrada para equilíbrio*/ public sincronizado void addamount (quantidade dupla) {duplo tmp = balance; tente {thread.sleep (10); } catch (interruptedException e) {e.printStackTrace (); } tmp += quantidade; balança = tmp; } /*Deduz dados recebidos do saldo do saldo* / public sincronizado void subtração (quantidade dupla) {duplo tmp = balance; tente {thread.sleep (10); } catch (interruptedException e) {e.printStackTrace (); } tmp -= valor; balança = tmp; } public Double getBalance () {return Balance; } public void SetBalance (Balance duplo) {this.Balance = Balance; }} /*Banco*/classe Banco implementa Runnable {Conta Private Conta; Public Bank (conta da conta) {this.account = conta; } @Override public void run () {for (int i = 0; i <100; i ++) {conta.subtractamount (1000); }}} /*Company*/Classe Company implementa Runnable {Conta Private Conta; empresa pública (conta de conta) {this.account = conta; } @Override public void run () {for (int i = 0; i <100; i ++) {conta.addamount (1000); }}}Você desenvolveu um aplicativo de simulação para contas bancárias que podem recarregar e deduzir os saldos. Este programa recarrega a conta chamando o método addamount () 100 vezes, depositando 1.000 de cada vez; Em seguida, deduz o saldo da conta chamando o método subtractamount () 100 vezes, deduzindo 1.000 de cada vez; Esperamos que o saldo final da conta seja igual ao saldo inicial e a implementamos através da palavra -chave sincronizada.
Se você deseja visualizar o problema de acesso simultâneo dos dados compartilhados, precisará excluir apenas as palavras -chave sincronizadas nas declarações de método addamount () e subtração (). Sem a palavra -chave sincronizada, o valor do equilíbrio impresso não é consistente. Se você executar este programa várias vezes, obterá resultados diferentes. Como a JVM não garante a ordem de execução dos threads, cada vez que é executado, os threads leem e modificam o saldo da conta em diferentes ordens, resultando em diferentes resultados finais.
O método de um objeto é declarado usando a palavra -chave sincronizado e só pode ser acessado por um thread. Se o thread A estiver executando um método de sincronização Syncmethoda (), o thread B deseja executar outros métodos de sincronização SyncmethodB () desse objeto, o encadeamento B será bloqueado até que o encadeamento A conclua o acesso. Mas se o Thread B acessar objetos diferentes da mesma classe, nenhum dos threads será bloqueado.
Exemplo 2
Demonstre o problema de que métodos sincronizados estáticos e métodos sincronizados não estáticos no mesmo objeto podem ser acessados por vários threads ao mesmo tempo. Verifique.
pacote concorrência; classe pública main8 {public static void main (string [] args) {conta de conta = new Account (); conta.setBalance (1000); Empresa da empresa = nova empresa (conta); Thread CompanyThread = new Thread (Empresa); Banco bancário = novo banco (conta); Thread BankThread = new Thread (banco); System.out.printf ("Conta: Balance Inicial: %f/n", Account.getBalance ()); Companythread.start (); BankThread.start (); tente {// junção () Método aguarda esses dois threads para concluir a CompanyThread.join (); BankThread.join (); System.out.printf ("Conta: Balanço Final: %f/n", Account.getBalance ()); } catch (interruptedException e) {e.printStackTrace (); }}} /*Conta*/Class Conta {/*Altere -a para uma variável estática aqui*/equilíbrio duplo estático privado = 0; /*Adicione dados de entrada ao saldo do equilíbrio, observe que eles são modificados com o vazio sincronizado estático*/ público addamount (quantidade dupla) {duplo tmp = balance; tente {thread.sleep (10); } catch (interruptedException e) {e.printStackTrace (); } tmp += quantidade; balança = tmp; } /*Deduz os dados recebidos do saldo do saldo* / public sincronizado void subtração (quantidade dupla) {duplo tmp = balance; tente {thread.sleep (10); } catch (interruptedException e) {e.printStackTrace (); } tmp -= valor; balança = tmp; } public Double getBalance () {return Balance; } public void SetBalance (Balance duplo) {this.Balance = Balance; }} /*Banco*/classe Banco implementa Runnable {Conta Private Conta; Public Bank (conta da conta) {this.account = conta; } @Override public void run () {for (int i = 0; i <100; i ++) {conta.subtractamount (1000); }}} /*Company*/Classe Company implementa Runnable {Conta Private Conta; empresa pública (conta de conta) {this.account = conta; } @Override public void run () {for (int i = 0; i <100; i ++) {conta.addamount (1000); }}}Acabei de adicionar a palavra -chave estática para modificar o saldo no exemplo anterior, e o método addamount () também pode modificar a palavra -chave estática. Você pode testar os resultados da execução e cada execução terá um resultado diferente!
Algum resumo: