No exemplo methodA e methodB são métodos de instância (em oposição a métodos estáticos). Colocar synchronized
um método de instância significa que o encadeamento precisa adquirir o bloqueio (o "bloqueio intrínseco") na instância do objeto em que o método é chamado antes que o encadeamento possa começar a executar qualquer código nesse método.
Se você tiver dois métodos de instância diferentes marcados como sincronizados e segmentos diferentes estiverem chamando esses métodos simultaneamente no mesmo objeto, esses segmentos estarão disputando o mesmo bloqueio. Depois que um thread obtém o bloqueio, todos os outros threads são excluídos de todos os métodos de instância sincronizados nesse objeto.
Para que os dois métodos sejam executados simultaneamente, eles precisam usar bloqueios diferentes, como este:
class A {
private final Object lockA = new Object();
private final Object lockB = new Object();
public void methodA() {
synchronized(lockA) {
//method A
}
}
public void methodB() {
synchronized(lockB) {
//method B
}
}
}
onde a sintaxe do bloco sincronizado permite especificar um objeto específico no qual o encadeamento em execução precisa adquirir o bloqueio intrínseco para entrar no bloco.
O importante é entender que, apesar de colocarmos uma palavra-chave "sincronizada" em métodos individuais, o conceito principal é o bloqueio intrínseco nos bastidores.
Aqui está como o tutorial Java descreve o relacionamento:
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.
O objetivo do bloqueio é proteger dados compartilhados. Você usaria bloqueios separados, como mostrado no código de exemplo acima, apenas se cada bloqueio protegesse diferentes membros de dados.