Dúvida com classe thread-safe!

15 respostas
Gustavo_Santos

Boa tarde galera, tenho uma duvida aqui :

public static synchronized void  metodo() {  }

Esse método obtem o bloqueio da instância java.lang.Class correto ?!

enquanto esse aqui:

public synchronized void  metodo() { }

que equivale a esse:

public void  metodo() {
		synchronized(this) { }
	}

Obtem o bloqueio da instância atual, this correto galera ?

15 Respostas

D

Gustavo Santos:
Boa tarde galera, tenho uma duvida aqui :

public static synchronized void  metodo() {  }

Esse método obtem o bloqueio da instância java.lang.Class correto ?!

enquanto esse aqui:

public synchronized static void  metodo() { }
public void  metodo() {
		synchronized(this) { }
	}

Obtem o bloqueio da instância atual, this correto galera ?

perfect

ou então outro bloqueo da sua classe

que equivale a esse:

public void  metodo() {  

synchronized(SuaClasse.class){}

}
Gustavo_Santos

Blz, já ajudou. Porém ainda tenho uma outra dúvida:

public class TestSeven extends Thread {
		private static int x; // UM CAMPO STATIC.

		public synchronized void doThings() { // MÉTODO NÃO STATIC ACESSANDO UM CAMPO STATIC. OBTEM O BLOQUEIO DO OBJETO ATUAL(THIS).      
			int current = x;
			current++;
			x = current;
		}
		public void run() {
			doThings();
		}

Declarar doThings () como método estático tornaria a classe thread-safe pelo fato de que :

Ao declarar doThings como estático, obtenho o bloqueio da Class.
Isso implica que qualquer outro método static da mesma intância ou de uma outra (do mesmo tipo)
não poderá executar esse método com um outro Thread por conta do bloqueio de Class.

Perguntas:
Isso está correto? Porque foi o que eu entendi.

E quanto aos métodos não estáticos, eles provavelmente bloquearam a instância this. De forma que ainda poderão
acessar a variável static. Isso não faz com que minha classe deixe de ser thread-safe ???

Grato a todos que ajudarem.

Gustavo_Santos

Alguém ? :roll:

evertonsilvagomesjav

Opa e ai Gustavo tudo bom?

Então um trecho de codigo se torna Thread safety se ele funcionar corretamente em execução simultânea por vários threads.

No caso que você citou, se você tiver métodos de instancia na classe TestSeven que acessam também sua variavel static, sua classe deixaria de ser Thread Safety pois alteraria o seu estado.

Nesse caso havendo métodos de instancia acessando sua variavel static private, se nao me engano essa classe entraria no tipo:

Hostil com threads, o que significa que sua classe não é segura em um ambiente mult threads, mesmo havendo sincronização em seus métodos.

ViniGodoy

Variáveis (estáticas ou não) só ficam thread safe se:

1. Todos os seus acessos forem sincronizados;
2. Toda sua sincronização se basear no mesmo monitor;

Se você usa um método não estático, cada sincronização terá um monitor diferente, o que viola a condição 2. Ou seja, se você tem 2 objetos A e B, a sincronização de A será feita sobre o objeto A, e a sincronização de B sobre o objeto B. Mas, como a variável estática é compartilhada por A e B, uma sincronização "local" não serve pois duas threads diferentes podem obter monitores diferentes, e usar a variável estática ao mesmo tempo, de maneira compartilhada. E isso acaba com a sua segurança.

Para resolver esse problema, você também precisa de um monitor compartilhado. Ou seja, basta usar um objeto que a e b compartilhem. O java sugere o uso do objeto Class() da sua classe, mas isso não é obrigatório. O importante apenas é que ambas as instâncias compartilhem o mesmo objeto, por exemplo:

public class TestSeven extends Thread {  
   private static int x; // UM CAMPO STATIC.  
   private static int[0] y = new int[0]; //Um objeto static qualquer.

   public void doThings() { 
      synchronized(y) { //Note que y é compartilhado entre todos os objetos da classe.
         int current = x;  
         current++;  
         x = current;  
      }  

      public void run() {  
         doThings();  
      }  
}

Deixar o método doThings() estático tem o mesmo efeito, por por padrão o Java irá fazer a sincronização em TestSeven.class, que também é compartilhado por ambos os objetos.

D
ViniGodoy:
Variáveis (estáticas ou não) só ficam thread safe se:

1. Todos os seus acessos forem sincronizados;
2. Toda sua sincronização se basear no mesmo monitor;

Se você usa um método não estático, cada sincronização terá um monitor diferente, o que viola a condição 2. Ou seja, se você tem 2 objetos A e B, a sincronização de A será feita sobre o objeto A, e a sincronização de B sobre o objeto B. Mas, como a variável estática é compartilhada por A e B, uma sincronização "local" não serve pois duas threads diferentes podem obter monitores diferentes, e usar a variável estática ao mesmo tempo, de maneira compartilhada. E isso acaba com a sua segurança.

Para resolver esse problema, você também precisa de um monitor compartilhado. Ou seja, basta usar um objeto que a e b compartilhem. O java sugere o uso do objeto Class() da sua classe, mas isso não é obrigatório. O importante apenas é que ambas as instâncias compartilhem o mesmo objeto, por exemplo:

public class TestSeven extends Thread {  
   private static int x; // UM CAMPO STATIC.  
   private static int[0] y = new int[0]; //Um objeto static qualquer.

   public void doThings() { 
      synchronized(y) { //Note que y é compartilhado entre todos os objetos da classe.
         int current = x;  
         current++;  
         x = current;  
      }  

      public void run() {  
         doThings();  
      }  
}

Deixar o método doThings() estático tem o mesmo efeito, por por padrão o Java irá fazer a sincronização em TestSeven.class, que também é compartilhado por ambos os objetos.

Mas nesse caso não adiantaria ele ter um bloqueio do Class(), pois se ele tivesse outro método de instancia que compartilha a variavel statica acabaria com a segurança também, é isso mesmo né?!

So funcionaria sincronizando um objeto compartilhado, igual vc fez.

D

Outra o que é hostil threads, que foi citado a cima?

Gustavo_Santos

Tudo bom sim Everton ! E mais uma vez brigadão A propósito,
minha prova está marcada para o dia 21 desse mes!!

Brigado também ViniGodoy, com essa explicação entendi um threcho de um código do livro
da Keity, cujo o qual, bloqueia o objeto System.out :

public void run() {
		synchronized(System.out) {
			
		}
	}


Para resolver esse problema, você também precisa de um monitor compartilhado. Ou seja, basta usar um objeto que a e b compartilhem. O java sugere o uso do objeto Class() da sua classe, mas isso não é obrigatório. O importante apenas é que ambas as instâncias compartilhem o mesmo objeto, por exemplo:

Esse também é o mesmo caso correto, o objeto out é compartilhado por a e b, não é ?!

ViniGodoy

Sim.

ViniGodoy

Dota:
Mas nesse caso não adiantaria ele ter um bloqueio do Class(), pois se ele tivesse outro método de instancia que compartilha a variavel statica acabaria com a segurança também, é isso mesmo né?!

So funcionaria sincronizando um objeto compartilhado, igual vc fez.

O bloqueio do Class funciona, pois o objeto class retornado é o mesmo para as duas instãncias, A e B. A variável estática estando completamente sincronizada nessas condições funciona perfeitamente.

D

Eu digo pelo fato de que se vc tem algo assim

public static void metodoStatico(){

synchronized(MinhaClasse.class){

acesso a variavel statica...

}

}
public synchronized void metodoNaoStatico(){

acesso á variavel statica...

}

Nesse caso Acima, um bloqueia this e outro o Class(), então nao funcionaria.

public static void metodoStatico(){

synchronized(objetoStatico){

acesso a variavel statica...

}

}
public void metodoNaoStatico(){

synchronized(ObjetoStatico){

acesso a variavel statica...
}

}

Acima agora funcionaria pois teria um monitor.

evertonsilvagomesjav

Gustavo Santos:
Tudo bom sim Everton ! E mais uma vez brigadão A propósito,
minha prova está marcada para o dia 21 desse mes!!

Brigado também ViniGodoy, com essa explicação entendi um threcho de um código do livro
da Keity, cujo o qual, bloqueia o objeto System.out :

public void run() {
		synchronized(System.out) {
			
		}
	}


Para resolver esse problema, você também precisa de um monitor compartilhado. Ou seja, basta usar um objeto que a e b compartilhem. O java sugere o uso do objeto Class() da sua classe, mas isso não é obrigatório. O importante apenas é que ambas as instâncias compartilhem o mesmo objeto, por exemplo:

Esse também é o mesmo caso correto, o objeto out é compartilhado por a e b, não é ?!

Você vai passar brother, certeza!

ViniGodoy

Como eu disse a regra é simples:

As instâncias das variáveis são sincronizadas pelo mesmo monitor? Se são, então é thread-safe.
Se não, então não são.

Se você tem dois métodos, um estático e outro não estático, como você colocou, usando só a synchronized na assinatura, um vai fazer sobre o Class e outro sobre o this. E, portanto, você tem a mesma instância (da variável estática) sendo “sincronizada” por dois monitores diferentes. E isso não é thread-safe, pois threads diferentes podem cada uma pegar um monitor diferente e entrar na região crítica.

Cuidado que essa é apenas uma regra de thread-safety. A segunda é que [b]todos[b] os locais que acessem a variável devem ser também sincronizados. Mesmo que sejam só para a leitura.

Agora, você poderia corrigir seu método não estático, forçando ele a usar o como monitor:

public void metodoNaoStatico(){  
   synchronized(getClass()){  
      acesso a variavel statica...  
   }  
}
ViniGodoy

Sim.

Só um comentário… apesar de isso ser possível é má pratica.
Uma boa idéia é você mesmo criar os objetos que serão usados como chaves, e especificamente com esse fim, ou usar o padrão do java (this e class).

Nada de ficar sincronizando JButtons, ou a variável que você vai fazer o acesso. Até porque, o padrão do Java torna essa prática extremamente perigosa…

D

Entendi cara, valeu.

Criado 1 de setembro de 2010
Ultima resposta 2 de set. de 2010
Respostas 15
Participantes 4