Pergunta

Qual poderia ser o entendimento dos seguintes?
Eu passei por isto Publique assim, mas ainda sem prendê -lo.

Code1:

synchronized(this){ 
// some code
}

Code2:

Object lock = new Object();

synchronized(lock){
// some code
}

Algum tutorial, ou alguns links para explicar sincronizados como eles explicarem a uma criança?

Foi útil?

Solução

Uma coisa não mencionada nas respostas excelentes já dadas é que a diferença entre o Code1 e o Code2. No Code1, a sincronização está na instância do objeto em que o código é encontrado e, no código2, está no objeto de bloqueio específico dentro do objeto.

Se houver apenas os dois blocos sincronizados na aula de anexo, não há funcional diferença entre os dois, mas considere o seguinte:

class CodeOneClass {
  ...
  synchronized(this) {   // or merely "synchronized" - it defaults to this
      first protected code block
  }
  ...
  synchronized(this) {   
      second protected code block
  }
...
}

class CodeTwoClass {
  ...
  Object lock1 = new Object();
  synchronized(lock1) {   
      first protected code block
  }
  ...
  Object lock2 = new Object();
  synchronized(lock2) {   
      second protected code block
  }
...
}

Se dois threads estão tentando usar a mesma instância de CodeoneClass, apenas um deles pode estar em qualquer um dos dois blocos de código protegidos ao mesmo tempo.

Mas com o segundo idioma, você tem a flexibilidade de dizer que é seguro para um tópico estar no primeiro bloco protegido e outro para estar no outro. Observe que, se os bloqueios fossem os mesmos (ambos sincronizando no mesmo objeto de bloqueio), o comportamento seria o primeiro.

Existem outras diferenças. Alguns escritores estão começando a apontar problemas com sincronizado (isso) - Eu apontaria para outro post aqui em SO:Evite sincronizado (isso) em Java?

Eu recomendo lê -lo e as três postagens às quais se vincula.

Outras dicas

Basicamente, há um "bloqueio" associado a todos os objetos em Java.

Quando um thread atinge uma chamada para sincronizada (algo), ele deve adquirir a trava de algo antes de continuar. Se você deseja permitir que apenas um thread de cada vez modifique o estado de um objeto, o mais óbvio é sincronizar a trava desse objeto. Se métodos diferentes puderem ser chamados em paralelo, você precisará de bloqueios diferentes para isso.

Se você escrever sincronizado (isso) ou simplesmente sincronizado, o thread deve adquirir o bloqueio associado ao objeto atual (do qual o método é chamado).

Observe que, como o Java 5.0, o pacote concorrente fornece adequadamente bloqueios que pode ser usado em vez de sincronização.

Colocando código dentro de um synchronized Block significa essencialmente: "Quando esse código começar a ser executado, outro código que precisa usar esse objeto não pode ser executado ao mesmo tempo".

Então, se o thread #2 estiver executando o código em seu code2 bloco, quando se trata do synchronized(lock) Código, ele deve observar efetivamente todos os outros threads para garantir que ninguém mais esteja executando o código "sincronizado" com o lock objeto no momento. O tópico nº 1 está certamente funcionando algum Código ao mesmo tempo, mas pode ser um código completamente não relacionado. Nesse caso, é seguro para o tópico nº 2 começar a executar o seu "some code" material.

Enquanto isso, se o thread #1 chegar ao synchronized(this) Block, ele também tem que fazer uma pausa e ver se outros threads estão usando this. Se this é o mesmo objeto que lock, nós temos um problema. Disseram -nos que apenas um thread pode usar esse objeto (em um bloco sincronizado) ao mesmo tempo. No entanto, o thread #2 já está usando. O tópico nº 1 terá que esperar ... e esperar ... e esperar ... até que eventualmente o Thread #2 termine. Então podemos prosseguir.

O resultado final é que apenas um synchronized O bloco pode ser executado de cada vez (com um objeto específico, é claro).

Suponha que você tenha um Account objeto que tem um método:

void debit(long debitAmount, Account beneficiary) throws InsufficientFundsException
{
   if (accountBalance >= debitAmount) {
      accountBalance -= debitAmount;
      beneficiary.credit(debitAmount);
   }
   else {
      throw new InsufficientFundsException();
   }
}

Agora, suponha que você tenha uma conta com um saldo de 100 euros, e você recebe duas tentativas de debitá -lo por 70 euros. Se os dois débitos ocorrerem ao mesmo tempo, você pode obter um condição de corrida assim:

  • Primeira verificação de débito Balance da conta: 100> = 70, então é bem -sucedido
  • Segunda verificação de débito Balance da conta: 100> = 70, então é bem -sucedido
  • O primeiro débito é executado; O saldo da conta se torna 30
  • Segundo débito é executado; O saldo da conta se torna -40. Não deve ser permitido

Podemos impedir esse estado terrível de coisas sincronizando no Account Bloqueio do objeto:

void debit(long debitAmount, Account beneficiary) throws InsufficientFundsException
{
   synchronized (this) {
      if (accountBalance >= debitAmount) {
         accountBalance -= debitAmount;
         beneficiary.credit(debitAmount);
      }
      else {
         throw new InsufficientFundsException();
      }
   }
}

Isso garante que o teste no saldo da conta e o débito não possam ser interrompidos por outro teste no saldo da conta.

o Tutorial Sun Java é um bom lugar para iniciar informações sobre simultaneidade e bloqueio.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top