Mais uma pergunta sobre synchronized

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:

[code]public void method (String key, int newValue) {

Object obj = Cache.getObject(key);
obj.setBla(newValue);
Cache.updateObject(key, obj);
}
[/code]
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

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

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

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.

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?

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.

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…

[quote=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… [/quote]

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.

verdade… melhor dar um shync nos 2 mesmo

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:

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?

Vai matar mesmo o desempenho?