Bloco sincronizado de Java para .class

102

O que esse código Java significa? Ele ganhará travamento em todos os objetos de MyClass?

synchronized(MyClass.class) {
   //is all objects of MyClass are thread-safe now ??
}

E como o código acima difere deste:

synchronized(this) {
   //is all objects of MyClass are thread-safe now ??
}
Andrew Tobilko
fonte

Respostas:

144

O snippet synchronized(X.class)usa a instância da classe como um monitor. Como há apenas uma instância de classe (o objeto que representa os metadados da classe em tempo de execução), um thread pode estar neste bloco.

Com synchronized(this)o bloqueio fica guardado pela instância. Para cada instância, apenas um thread pode entrar no bloco.

synchronized(X.class)é usado para garantir que haja exatamente um Thread no bloco. synchronized(this)garante que haja exatamente um encadeamento por instância. Se isso torna o código real no bloco seguro para thread, depende da implementação. Se mutate, apenas o estado da instância synchronized(this)é suficiente.

Thomas Jung
fonte
6
"tantos threads podem entrar no bloco quantas forem as instâncias" implica que a segunda forma atua como um semáforo, o que não é verdadeiro. Você deve dizer algo como: "synchronized (this) garante que apenas um thread pode entrar no bloco para uma determinada instância da classe".
liwp
Corrigido. Eu pretendia dizer isso.
Thomas Jung
2
qual é a instância da classe vs a instância?
Weishi Zeng
Portanto, se você tiver um método estático e não quiser sincronizar todo o seu corpo, sincronizar (isso) não é bom, em vez disso, sincronizar (Foo.class) é apropriado. Isso está certo?
krupal.agile
84

Para adicionar às outras respostas:

static void myMethod() {
  synchronized(MyClass.class) {
    //code
  }
}

é equivalente a

static synchronized void myMethod() {
  //code
}

e

void myMethod() {
  synchronized(this) {
    //code
  }
}

é equivalente a

synchronized void myMethod() {
  //code
}
Jorn
fonte
12
Levei uma segunda leitura para perceber que os primeiros dois exemplos têm a palavra-chave "estático". Apenas apontando isso para outras pessoas que podem ter visto isso e não percebido. Sem a palavra-chave estática, os primeiros dois exemplos não seriam os mesmos.
kurtzbot
1
Esses exemplos NÃO são equivalentes! Os métodos sincronizados são "sincronizados" como um buraco quando um thread tenta chamar os métodos. Os blocos, por outro lado, podem ter código acima e abaixo deles, que podem ser executados a partir de vários threads. Eles só sincronizam dentro do bloco! Isso não é o mesmo!
JacksOnF1re
public static Singleton getInstance () {if (instância == null) {synchronized (Singleton.class) {instance = new Singleton (); }} instância de retorno; }
JacksOnF1re
2
A questão toda é que não é nenhum código fora dos synchronizedblocos. Isso os torna equivalentes. Se você mudar um exemplo, eles realmente não são mais os mesmos.
Jorn
22

Não, o primeiro obterá um bloqueio na definição de classe de MyClass, nem todas as instâncias dela. No entanto, se usado em uma instância, isso bloqueará efetivamente todas as outras instâncias, uma vez que compartilham uma única definição de classe.

O segundo obterá um bloqueio apenas na instância atual.

Se isso torna seu thread de objetos seguro, essa é uma questão muito mais complexa - precisaríamos ver seu código!

David M
fonte
1
sim, MyClass.class pode ser qualquer variável estática e ter o mesmo efeito.
pstanton