Métodos estáticos sincronizados em Java: bloquear objeto ou classe

148

A documentação do Java diz:

Não é possível intercalar duas invocações de métodos sincronizados no mesmo objeto.

O que isso significa para um método estático? Como um método estático não possui um objeto associado, a palavra-chave sincronizada será bloqueada na classe, em vez do objeto?

jbu
fonte

Respostas:

129

Como um método estático não possui um objeto associado, a palavra-chave sincronizada será bloqueada na classe, em vez do objeto?

Sim. :)

OscarRyz
fonte
81
Por favor, responda Elaborado para que todos possam entender.
Madhu
6
@Madhu. Isso significa que, se você tiver 2 ou mais métodos sincronizados na mesma classe, ambos não poderão ser executados ao mesmo tempo, mesmo quando houver várias instâncias dessa classe. O bloqueio é essencialmente o mesmo que o bloqueio no Object.class para cada método sincronizado.
1616 Steven
Esta resposta está errada - thisé o bloqueio adquirido nos métodos de instância -, por favor, corrija-o Oscar.
vemv 31/10/12
1
@vemv A questão é sobre métodos de classe, não métodos de instância.
OscarRyz 31/10/12
23
@vemv Bem, sim, para entender a resposta, você deve ler a pergunta primeiro.
OscarRyz 31/10/12
199

Apenas para adicionar um pequeno detalhe à resposta de Oscar (agradavelmente sucinta!), A seção relevante na Especificação da linguagem Java é 8.4.3.6, 'Métodos sincronizados' :

Um método sincronizado adquire um monitor ( §17.1 ) antes de executar. Para um método de classe (estático), o monitor associado ao objeto Class para a classe do método é usado. Para um método de instância, o monitor associado a este (o objeto para o qual o método foi chamado) é usado.

Cowan
fonte
17
Útil, eu estava procurando essa citação +1
OscarRyz 13/01/09
80

Um ponto sobre o qual você deve ter cuidado (vários programadores geralmente caem nessa armadilha) é que não há vínculo entre métodos estáticos sincronizados e métodos não estáticos sincronizados, ou seja:

class A {
    static synchronized f() {...}
    synchronized g() {...}
}

A Principal:

A a = new A();

Tópico 1:

A.f();

Tópico 2:

a.g();

f () eg () não são sincronizados entre si e, portanto, podem ser executados de forma totalmente simultânea.

jfpoilpret
fonte
18
mas e se g () estiver modificando alguma variável estática que f () esteja lendo. Como tornamos esse segmento seguro? Adquirimos explicitamente um bloqueio na classe?
baskin
22
Sim, seu método não estático deve sincronizar explicitamente a própria classe (ou seja synchronized (MyClass.class) {...},.
jfpoilpret
@jfpoilpret "sincronizado (MyClass.class) {...}" é equivalente a tornar este método estático sincronizado, certo?
crazymind
15

A menos que você implemente g () da seguinte maneira:

g() {
    synchronized(getClass()) {
        ...
    }
}

Acho esse padrão útil também quando quero implementar exclusão mútua entre diferentes instâncias do objeto (o que é necessário ao acessar um recurso externo, por exemplo).

finalmente tente
fonte
63
Observe que, na verdade, pode haver uma chance de alguns erros muito sutis e desagradáveis ​​aqui. Remember getClass()retorna o tipo de tempo de execução ; se você subclassificar a classe, a classe pai e a classe filho serão sincronizadas em bloqueios diferentes. synchronized(MyClass.class)é o caminho a percorrer se você precisar garantir que todas as instâncias usem o mesmo bloqueio.
Cowan
4

Dê uma olhada na página de documentação da Oracle em Bloqueios intrínsecos e sincronização

Você pode se perguntar o que acontece quando um método sincronizado estático é chamado, já que um método estático está associado a uma classe, não a um objeto. Nesse caso, o encadeamento adquire o bloqueio intrínseco para o objeto Class associado à classe . Portanto, o acesso aos campos estáticos da classe é controlado por um bloqueio distinto do bloqueio para qualquer instância da classe .

Ravindra babu
fonte
2

Um método estático também tem um objeto associado. Pertence ao arquivo Class.class no kit de ferramentas JDK. Quando o arquivo .class é carregado no ram, o Class.class cria uma instância chamada objeto de modelo.

Por exemplo: - quando você tenta criar um objeto da classe de cliente existente, como

Customer c = new Customer();

O Customer.class é carregado na RAM. Nesse momento, Class.class no JDK toolkit cria um objeto chamado Template objeto e carrega esse Customer.class nesse objeto de modelo. Os membros estáticos dessa Customer.class tornam-se atributos e métodos nesse objeto de modelo.

Portanto, um método ou atributo estático também tem um objeto

Pahansith Gunathilake
fonte
2

Os exemplos abaixo dão mais clareza entre bloqueio de classe e objeto; a esperança de que o exemplo abaixo também ajude outras pessoas :)

Por exemplo, temos os métodos abaixo: uma classe de aquisição e outra aquisição de bloqueio de objeto:

public class MultiThread {

    public static synchronized void staticLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }

    public synchronized void objLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

Portanto, agora podemos ter os seguintes cenários:

  1. Quando threads que usam o mesmo objeto tentam acessar o método objLock OR ao staticLock mesmo tempo (ou seja, ambos os threads estão tentando acessar o mesmo método)

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
  2. Quando threads usando o mesmo objeto tentam acessar staticLocke objLockmétodos ao mesmo tempo (tentam acessar métodos diferentes)

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4
  3. Quando threads usando Object diferente tentam acessar o staticLockmétodo

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
  4. Quando threads usando Object diferente tentam acessar o objLockmétodo

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4
Ravi
fonte
0

Para aqueles que não são familiarizados com o método sincronizado estático bloqueado no objeto de classe, por exemplo, para a classe string, seu String.class enquanto o método sincronizado de instância bloqueia a instância atual de Object denotada pela palavra-chave "this" em Java. Como os dois objetos são diferentes, eles têm bloqueios diferentes. Enquanto um thread executa o método estático sincronizado, outro thread no java não precisa esperar o retorno do thread; ele adquirirá literalmente byte .class de bloqueio separado e entrará em método sincronizado estático.

Pragya
fonte