Alguém pode me dizer a vantagem do método sincronizado sobre o bloco sincronizado com um exemplo?
java
multithreading
concurrency
locking
synchronized
Guerreiro
fonte
fonte
Respostas:
Não há uma clara vantagem de usar o método sincronizado sobre o bloco.
Talvez o único (mas eu não chamaria isso de vantagem) é que você não precisa incluir a referência do objeto
this
.Método:
Quadra:
Vejo? Nenhuma vantagem.
Blocos que têm vantagens sobre os métodos, porém, principalmente na flexibilidade porque você pode usar outro objeto como bloqueio enquanto sincronizar o método seria bloquear todo o objeto.
Comparar:
vs.
Além disso, se o método crescer, você ainda poderá manter a seção sincronizada separada:
fonte
synchronized
bloco é implementado usando duas instruçõesmonitorenter
emonitorexit
, além de um manipulador de exceções que garante que issomonitorexit
seja chamado mesmo no caso excepcional. Tudo isso é salvo ao usar umsynchronized
método.A única diferença real é que um bloco sincronizado pode escolher em qual objeto ele será sincronizado. Um método sincronizado pode usar apenas
'this'
(ou a instância de Class correspondente para um método de classe sincronizado). Por exemplo, estes são semanticamente equivalentes:O último é mais flexível, pois pode competir pelo bloqueio associado de qualquer objeto, geralmente uma variável de membro. Também é mais granular porque você pode ter código simultâneo executando antes e depois do bloco, mas ainda dentro do método. Obviamente, você poderia facilmente usar um método sincronizado refatorando o código simultâneo em métodos não sincronizados separados. Use o que tornar o código mais compreensível.
fonte
Método Sincronizado
Prós:
Contras:
Bloco sincronizado
Prós:
Contras:
Pessoalmente, prefiro usar métodos sincronizados com classes focadas apenas na coisa que precisa de sincronização. Essa classe deve ser a menor possível e, portanto, deve ser fácil revisar a sincronização. Outros não precisam se preocupar com a sincronização.
fonte
A principal diferença é que, se você usar um bloco sincronizado, poderá bloquear um objeto que não seja o que permite ser muito mais flexível.
Suponha que você tenha uma fila de mensagens e vários produtores e consumidores de mensagens. Não queremos que os produtores interfiram entre si, mas os consumidores devem poder recuperar mensagens sem ter que esperar pelos produtores. Então, nós apenas criamos um objeto
E a partir de agora, toda vez que um produtor quiser adicionar uma nova mensagem, apenas bloqueamos:
Portanto, os consumidores ainda podem ler e os produtores serão bloqueados.
fonte
Método sincronizado
Métodos sincronizados têm dois efeitos.
Primeiro, quando um encadeamento está executando um método sincronizado para um objeto, todos os outros encadeamentos que invocam métodos sincronizados para o mesmo bloco de objetos (suspender a execução) até que o primeiro encadeamento seja concluído com o objeto.
Segundo, quando um método sincronizado sai, ele estabelece automaticamente um relacionamento de antes do acontecimento com qualquer chamada subsequente de um método sincronizado para o mesmo objeto. Isso garante que as alterações no estado do objeto sejam visíveis para todos os threads.
Observe que os construtores não podem ser sincronizados - o uso da palavra-chave sincronizada com um construtor é um erro de sintaxe. Sincronizar construtores não faz sentido, porque apenas o encadeamento que cria um objeto deve ter acesso a ele enquanto está sendo construído.
Instrução Sincronizada
Diferentemente dos métodos sincronizados, as instruções sincronizadas devem especificar o objeto que fornece o bloqueio intrínseco: Na maioria das vezes, eu uso isso para sincronizar o acesso a uma lista ou mapa, mas não quero bloquear o acesso a todos os métodos do objeto.
P: Bloqueios intrínsecos e sincronização A sincronização é criada em torno de uma entidade interna conhecida como bloqueio intrínseco ou bloqueio do monitor. (A especificação da API geralmente se refere a essa entidade simplesmente como um "monitor".) Os bloqueios intrínsecos desempenham um papel em ambos os aspectos da sincronização: impor acesso exclusivo ao estado de um objeto e estabelecer relacionamentos anteriores ao passado, essenciais para a visibilidade.
Todo objeto tem um bloqueio intrínseco associado a ele. Por convenção, um encadeamento que precisa de acesso exclusivo e consistente aos campos de um objeto precisa adquirir o bloqueio intrínseco do objeto antes de acessá-los e liberar o bloqueio intrínseco quando terminar com eles. Diz-se que uma linha possui a trava intrínseca entre o momento em que ela adquiriu a trava e a liberou. Desde que um encadeamento possua um bloqueio intrínseco, nenhum outro encadeamento poderá adquirir o mesmo bloqueio. O outro encadeamento será bloqueado quando tentar obter o bloqueio.
Verifique as saídas diferentes com o método sincronizado, em bloco e sem sincronização.
fonte
Nota: métodos e blocos estáticos sincronizados funcionam no objeto Class.
fonte
Quando o compilador java converte seu código-fonte em código de bytes, ele lida com métodos e blocos sincronizados de maneira muito diferente.
Quando a JVM executa um método sincronizado, o encadeamento em execução identifica que a estrutura method_info do método possui o sinalizador ACC_SYNCHRONIZED definido e adquire automaticamente o bloqueio do objeto, chama o método e libera o bloqueio. Se ocorrer uma exceção, o encadeamento libera automaticamente o bloqueio.
A sincronização de um bloco de método, por outro lado, ignora o suporte interno da JVM para adquirir o manuseio de bloqueio e exceção de um objeto e requer que a funcionalidade seja explicitamente escrita em código de bytes. Se você ler o código de bytes de um método com um bloco sincronizado, verá mais de uma dúzia de operações adicionais para gerenciar essa funcionalidade.
Isso mostra as chamadas para gerar um método sincronizado e um bloco sincronizado:
O
synchronizedMethodGet()
método gera o seguinte código de bytes:E aqui está o código de bytes do
synchronizedBlockGet()
método:Uma diferença significativa entre o método sincronizado e o bloco é que, geralmente, o bloco sincronizado reduz o escopo do bloqueio. Como o escopo do bloqueio é inversamente proporcional ao desempenho, é sempre melhor bloquear apenas uma seção crítica do código. Um dos melhores exemplos de uso do bloco sincronizado é o bloqueio verificado duas vezes no padrão Singleton, onde, em vez de bloquear todo o
getInstance()
método, apenas bloqueamos a seção crítica do código que é usada para criar a instância Singleton. Isso melhora drasticamente o desempenho, porque o bloqueio é necessário apenas uma ou duas vezes.Ao usar métodos sincronizados, você precisará ter cuidado extra se misturar métodos sincronizados estáticos e não estáticos.
fonte
monitorenter
emonitorexit
antes de executar o código.Na maioria das vezes eu uso isso para sincronizar o acesso a uma lista ou mapa, mas não quero bloquear o acesso a todos os métodos do objeto.
No código a seguir, um thread modificando a lista não bloqueará a espera de um thread que está modificando o mapa. Se os métodos foram sincronizados no objeto, cada método teria que esperar, mesmo que as modificações que estão fazendo não entrem em conflito.
fonte
Com blocos sincronizados, você pode ter vários sincronizadores, para que várias coisas simultâneas, mas não conflitantes, possam continuar ao mesmo tempo.
fonte
Métodos sincronizados podem ser verificados usando a API de reflexão. Isso pode ser útil para testar alguns contratos, como todos os métodos no modelo são sincronizados .
O seguinte fragmento imprime todos os métodos sincronizados do Hashtable:
fonte
Nota importante sobre o uso do bloco sincronizado: cuidado com o que você usa como objeto de bloqueio!
O trecho de código do usuário2277816 acima ilustra esse ponto em que uma referência a um literal de seqüência de caracteres é usada como objeto de bloqueio. Perceba que os literais de strings são automaticamente internados em Java e você deve começar a ver o problema: todo trecho de código que é sincronizado no "bloqueio" literal, compartilha o mesmo bloqueio! Isso pode facilmente levar a conflitos com trechos de código completamente não relacionados.
Não são apenas os objetos String que você precisa ter cuidado. As primitivas in a box também são um perigo, pois a caixa automática e os métodos valueOf podem reutilizar os mesmos objetos, dependendo do valor.
Para obter mais informações, consulte: https://www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+be+reused
fonte
Geralmente, o uso de uma trava no nível do método é muito rude. Por que bloquear um código que não acessa nenhum recurso compartilhado bloqueando um método inteiro. Como cada objeto possui um bloqueio, é possível criar objetos fictícios para implementar a sincronização no nível do bloco. O nível do bloco é mais eficiente porque não bloqueia todo o método.
Aqui algum exemplo
Nível do método
Nível do bloco
[Editar]
Para
Collection
gostarVector
eHashtable
eles são sincronizados quandoArrayList
ouHashMap
não, e você precisa definir a palavra-chave sincronizada ou invocar o método sincronizado de Coleções:fonte
A única diferença: os blocos sincronizados permitem o bloqueio granular, diferentemente do método sincronizado
Basicamente
synchronized
, métodos ou blocos foram usados para escrever código seguro de thread, evitando erros de inconsistência de memória.Esta questão é muito antiga e muitas coisas foram alteradas nos últimos 7 anos. Novas construções de programação foram introduzidas para segurança do encadeamento.
Você pode obter segurança de encadeamento usando API de simultaneidade avançada em vez de
synchronied
blocos. Esta página de documentação fornece boas construções de programação para garantir a segurança do encadeamento.Os objetos de bloqueio oferecem suporte a idiomas de bloqueio que simplificam muitos aplicativos simultâneos.
Os executivos definem uma API de alto nível para iniciar e gerenciar threads. As implementações de executores fornecidas pelo java.util.concurrent fornecem gerenciamento de conjunto de encadeamentos adequado para aplicativos de grande escala.
Coleções simultâneas facilitam o gerenciamento de grandes coleções de dados e podem reduzir bastante a necessidade de sincronização.
As variáveis atômicas possuem recursos que minimizam a sincronização e ajudam a evitar erros de consistência de memória.
O ThreadLocalRandom (no JDK 7) fornece geração eficiente de números pseudo-aleatórios a partir de vários encadeamentos.
Melhor substituto para o sincronizado é o ReentrantLock , que usa
Lock
APIExemplo com bloqueios:
Consulte java.util.concurrent e java.util.concurrent.atomic pacotes também para outras construções de programação.
Consulte também esta questão relacionada:
Sincronização vs Bloqueio
fonte
O método sincronizado é usado para bloquear todos os objetos. O bloco sincronizado é usado para bloquear objetos específicos.
fonte
Em geral, eles são basicamente os mesmos, exceto por serem explícitos sobre o monitor do objeto que está sendo usado versus o implícito desse objeto. Uma desvantagem dos métodos sincronizados que eu acho que às vezes é negligenciada é que, ao usar a referência "this" para sincronizar, você deixa em aberto a possibilidade de objetos externos travarem no mesmo objeto. Isso pode ser um bug muito sutil, se você o encontrar. A sincronização em um objeto explícito interno ou em outro campo existente pode evitar esse problema, encapsulando completamente a sincronização.
fonte
Como já foi dito aqui, o bloco sincronizado pode usar a variável definida pelo usuário como objeto de bloqueio, quando a função sincronizada usa apenas "this". E é claro que você pode manipular com áreas de sua função que devem ser sincronizadas. Mas todo mundo diz que não há diferença entre a função sincronizada e o bloco, que cobre toda a função usando "this" como objeto de bloqueio. Isso não é verdade, a diferença está no código de bytes que será gerado nas duas situações. No caso de uso sincronizado de blocos, deve ser alocada uma variável local que contém referência a "this". E, como resultado, teremos um tamanho um pouco maior para a função (não relevante se você tiver apenas um pequeno número de funções).
Explicação mais detalhada da diferença que você pode encontrar aqui: http://www.artima.com/insidejvm/ed2/threadsynchP.html
fonte
No caso de métodos sincronizados, o bloqueio será adquirido em um Objeto. Mas se você optar pelo bloco sincronizado, terá a opção de especificar um objeto no qual o bloqueio será adquirido.
Exemplo:
fonte
Sei que essa é uma pergunta antiga, mas com a rápida leitura das respostas aqui, não vi ninguém mencionar que, às vezes, um
synchronized
método pode ser o bloqueio errado .Na Concorrência Java na prática (pág. 72):
O código acima parece ser seguro para threads. No entanto, na realidade não é. Nesse caso, o bloqueio é obtido na instância da classe. No entanto, é possível que a lista seja modificada por outro encadeamento que não use esse método. A abordagem correta seria usar
O código acima impediria que todos os threads que tentassem modificar a lista modificassem a lista até que o bloco sincronizado fosse concluído.
fonte
List
pode levar a problemas de desempenho se houver um registro de código que não necessariamente precisam ser sincronizadosPor uma questão prática, a vantagem dos métodos sincronizados sobre os blocos sincronizados é que eles são mais resistentes a idiotas; porque você não pode escolher um objeto arbitrário para bloquear, não pode usar indevidamente a sintaxe do método sincronizado para fazer coisas estúpidas, como bloquear uma literal de string ou bloquear o conteúdo de um campo mutável que é alterado sob os threads.
Por outro lado, com métodos sincronizados, você não pode impedir que o bloqueio seja adquirido por qualquer thread que possa obter uma referência ao objeto.
Portanto, usar a sincronização como um modificador nos métodos é melhor para proteger seus cow-orkers de se machucarem, enquanto o uso de blocos sincronizados em conjunto com objetos de bloqueio final privados é melhor para proteger seu próprio código dos cow-orkers.
fonte
Em um resumo de especificação Java: http://www.cs.cornell.edu/andru/javaspec/17.doc.html
Com base nessas descrições, eu diria que a maioria das respostas anteriores está correta, e um método sincronizado pode ser particularmente útil para métodos estáticos, onde você teria que descobrir como obter o "objeto de classe que representa a classe na qual o método estava" definiram."
Edit: Eu originalmente pensei que estas eram citações da especificação Java real. Esclareceu que esta página é apenas um resumo / explicação das especificações
fonte
TLDR; Não use o
synchronized
modificador nem asynchronized(this){...}
expressão, massynchronized(myLock){...}
ondemyLock
existe um campo de instância final contendo um objeto particular.A diferença entre o uso do
synchronized
modificador na declaração do método e asynchronized(..){ }
expressão no corpo do método é a seguinte:synchronized
modificador especificado na assinatura do métodosynchronized(this) { .... }
, ethis
objeto como bloqueio quando declarado em método não estático ou a classe envolvente quando declarado em método estático.synchronized(...){...}
expressão permite que vocêNo entanto, o uso do
synchronized
modificador ousynchronized(...) {...}
comthis
o objeto de bloqueio (como emsynchronized(this) {...}
) tem a mesma desvantagem. Ambos usam sua própria instância como o objeto de bloqueio para sincronização. Isso é perigoso porque não apenas o objeto em si, mas qualquer outro objeto / código externo que contenha uma referência a esse objeto também pode usá-lo como um bloqueio de sincronização com efeitos colaterais potencialmente graves (degradação do desempenho e conflitos ).Portanto, a melhor prática é não usar o
synchronized
modificador nem asynchronized(...)
expressão em conjunto comthis
como objeto de bloqueio, mas um objeto de bloqueio privado para esse objeto. Por exemplo:Você também pode usar vários objetos de bloqueio, mas é necessário tomar cuidado especial para garantir que isso não resulte em conflitos quando usados aninhados.
fonte
Suponho que esta pergunta seja sobre a diferença entre o Thread Safe Singleton e a inicialização Lazy com bloqueio de verificação dupla . Sempre me refiro a este artigo quando preciso implementar algum singleton específico.
Bem, este é um Singleton seguro para threads :
Esta é uma inicialização lenta com bloqueio de verificação dupla :
Consulte este artigo para obter mais detalhes:
https://www.geeksforgeeks.org/java-singleton-design-pattern-practices-examples/
fonte
Sincronizando com threads. 1) NUNCA use sincronizado (isto) em um thread que não funcione. A sincronização com (this) usa o encadeamento atual como o objeto de encadeamento. Como cada segmento é independente de outros segmentos, NÃO há coordenação de sincronização. 2) Testes de código mostram que no Java 1.6 em um Mac a sincronização do método não funciona. 3) sincronizado (lockObj), em que lockObj é um objeto compartilhado comum de todos os threads sincronizados nele. 4) ReenterantLock.lock () e .unlock () funcionam. Veja os tutoriais de Java para isso.
O código a seguir mostra esses pontos. Ele também contém o vetor de thread-safe que seria substituído pelo ArrayList, para mostrar que muitos threads adicionados a um Vector não perdem nenhuma informação, enquanto o mesmo com um ArrayList pode perder informações. 0) O código atual mostra a perda de informações devido às condições da corrida. A) Comente a linha A atualmente rotulada e remova o comentário da linha A acima dela, depois execute, o método perde dados, mas não deve. B) Inverta a etapa A, remova o comentário B e // finalize o bloco}. Em seguida, execute para ver os resultados sem perda de dados. C) Comente B, descomente C. Execute, veja a sincronização em (isto) perde dados, conforme o esperado. Não tenha tempo para concluir todas as variações, espero que ajude. Se a sincronização estiver ativada (isto) ou a sincronização do método funcionar, indique qual versão do Java e do SO você testou. Obrigado.
fonte