Mais uma pergunta sobre synchronized

11 respostas
roberto_sc

Olás

Estou fazendo um stateless bean que possui 2 métodos que têm conflito: ambos acessam um objeto e o atualizam. Seria mais ou menos assim:
public void method (String key, int newValue) {

Object obj = Cache.getObject(key);
obj.setBla(newValue);
Cache.updateObject(key, obj);
}
Então ambos métodos pegam uma instância de um objeto que está armazenada num repositório e o modifica. Um dos métodos é chamado o tempo todo, o outro quase nunca. Porém ambos não podem ser executados simultaneamente (pelo menos não com a mesma instância - mesmo key).

- Como solucionar o problema? Sincronizar os dois médotos vai matar o desempenho, a classe é um stateless bean e um dos métodos é chamado com grande frequencia...
- Existe uma maneira de usar a instância do obj como lock da sincronização e assim fazer com que os 2 métodos possam ser executados simultaneamente exceto quando os obj possuem a mesma key?

Obrigado

11 Respostas

T

nao sei se entendi a pergunta mas uma ideia seria usar um bloco sincronizado dentro do metodo ao inves de sincronizar o metodo por exemplo sincronized(meuObjeto){ …} , talvez metodos como wait e notify possam ajudar

fantomas

Acho q não entendi direito. Vc tem 2 métodos executando este método que vc citou, é isso?

Outra coisa neste método q vc escreveu, acho que não precisa do Cache.updateObject(key,obj) caso ele esteja retornando apenas a referencia do obj, se for um novo ai beleza.

Diz ai…

flws

otavio

Na verdade quem tem que ser sincronizado é teu objeto e não o método.

Sincronizar o método vai controlar o acesso no método, não no objeto. Mas… lembre-se que usar atributos static nos EJBs e modificar instâncias viola a especificação, pois caso for usado cluster você vai alterar o valor desse objeto apenas no nó corrente.

roberto_sc

Explicando melhor:

  • São 2 métodos diferentes no mesmo EJB, esse método que eu postei é só um exemplo de como mais ou menos eles são. Estes dois métodos podem ser executados simultaneamente e modificar o obj, e daí vem o problema.

  • O Cache implementado aqui funciona assim, é necessário o update mesmo.

  • Obrigado pela dica do static, nós realmente vamos usar cluster!

Pensei que uma solução seria fazer isso, em cada um dos 2 métodos:

public void method (String key, int newValue) {
syncronized(obj) { //hmm that wont work... :(
Object obj = Cache.getObject(key);
obj.setBla(newValue);
Cache.updateObject(key, obj);
}
}

Mas isso não vai funcionar, certo?

M

Tente inverter as linhas: primeiro você pega um objeto do Cache, e usa-o como lock para a mudança que deve ser sincronizada. E observe a dica de fantomas. Algo como:

public void method (String key, int newValue) {
Object obj = Cache.getObject(key);
syncronized(obj) {
obj.setBla(newValue);
Cache.updateObject(key, obj); // essa linha será realmente necessária?
}
}

Não tenho certeza, mas acho que isso pode ajudar.

Lavieri

se o seu problema especifico é so nesses 2 metodos… e so quando os 2 ocorrem simultaneamente…

e vc tem 1 método que é menos frequente… coloque o sync apenas no método menos frequente… e so na parte do uso do objeto… isso para priorizar o desempenho… assim vc so vai travar o objeto, quando estiver usando o método menos frequente, ou seja… e talvez ajude no seu desempenho…

M

Lavieri:
se o seu problema especifico é so nesses 2 metodos… e so quando os 2 ocorrem simultaneamente…

e vc tem 1 método que é menos frequente… coloque o sync apenas no método menos frequente… e so na parte do uso do objeto… isso para priorizar o desempenho… assim vc so vai travar o objeto, quando estiver usando o método menos frequente, ou seja… e talvez ajude no seu desempenho…

Mas isso pode dar problema… pense comigo:
O metodo1() é o chamado com frequência enquanto o metodo2() é chamado só as vezes. Na execução do programa teríamos uma sequência de chamadas como, por exemplo:

metodo1() 
metodo1() 
metodo1() 
metodo1() 
metodo1() 
metodo1()
metodo1()
metodo1()
metodo1()
metodo1()
metodo2() // ==> essa chamada do metodo2 foi feita enquanto o metodo1 estava em execução (no meio do método)
metodo1()

Acontece que o metodo2, nesse caso, conseguirá tranquilamente o lock do objeto, uma vez que o metodo1 não é sincronizado (ou seja não requer o lock de objeto algum). Com isso, a execução do metodo1 seria interrompida no meio, o metodo2 seria todo executado e a execução do metodo1 seria retomada, dando inconsistência nos dados. Creio que os dois métodos devem ter um trecho sincronizado para evitar problemas como esse.

Lavieri

verdade… melhor dar um shync nos 2 mesmo

otavio

A opensynphony possui uma lib para cache que é a Oscache, que suporta cluster e tudo mais. Não conheço o teu projeto, mas creio que usar uma lib com a Oscache é uma boa, pois ela é bem testada e até o Hibernate usa ela.

A lib ehcache não possui suporte a cluster se não me engano.

Creio que usando uma lib dessas você pode trabalhar melhor nas regras de negócio e deixa que a Oscache faça o trabalho pesado :slight_smile:

roberto_sc

Obrigado pessoal.
Nos estamos usando o POJO Cache da JBoss, vcs sabem se ele tem alguma coisa para cuidar dessa parte de lock dos objetos?

B

Vai matar mesmo o desempenho?

Criado 6 de fevereiro de 2009
Ultima resposta 9 de fev. de 2009
Respostas 11
Participantes 7