Synchronized + web + objetos de negócio

Dae galera, eu estou estudando um pouco sobre Threads e sincronização e me ocorreu a seguinte dúvida:

Como eu faço para sincronizar objetos de negócio utilizando por exemplo os Managed Bean do jsf ou o próprio Servlet?

Exemplo com Managed Bean:

[code]// Managed Bean com escopo de request
public class ContaMB implements Serializable {

private ContaService service = new ContaService();
private Conta conta;

public String debitar() {
	FacesContext context = // Recupera o usuário logado por exemplo
	Usuario usuario = context....
	this.service.debitar( this.getConta().getValor(), usuario.getCodUsuario());	
                            return null;
}

}[/code]

[code]// Service da conta
public class ContaService {

private RepositorioConta repositorio = null;

public void debitar( double valorADebitar, int codigoUsuario ) throws Exception {
	// Verifica o usuario ....

	// Verifica saldo atual
	double saldoAtual = this.getSaldoAtual(codigoUsuario);

	// Verifica se pode debitar da conta
	if( saldoAtual > valorADebitar) {
		repositorio.debita(valorADebitar, codigoUsuario);			
	} else {
		throw new Exception("Saldo Insuficiente");
	}
}

}[/code]
Como poderei sincronizar por exemplo o meu método debitar da classe ContaService sendo que cada requisição é uma Thread e consequentemente um novo objeto?

Assim funciona?:

[code]public class ContaService {

private RepositorioConta repositorio = null;

// Foi colocado o synchronized
public synchronized void debitar( double valorADebitar, int codigoUsuario ) throws Exception {
	// Verifica o usuario ....

	// Verifica saldo atual
	double saldoAtual = this.getSaldoAtual(codigoUsuario);

	// Verifica se pode debitar da conta
	if( saldoAtual > valorADebitar) {
		repositorio.debita(valorADebitar, codigoUsuario);			
	} else {
		throw new Exception("Saldo Insuficiente");
	}
}

}[/code]

A questão aqui é que cada requisição cria uma classe do ManagedBean e também do service, eu quero por exemplo conseguir evitar que outro browser logado com meu usuário consiga fazer o débito de forma que os dados fiquem inconsistentes.
Ah… desculpem algum erro no código, é que escrevi direto aqui no guj.
Abraço e valeu pela ajuda.

Dae galera… continuo procurando e nada.
Alguém tem idéia de como fazer?

Você tem diversos jeitos para implementar isso.
O mais básico que eu vejo é ter um pseudo “monitor”.

em uma classe você o cria e sincroniza ele para realizar uma operação A

private Object monitor;

public void operacaoA(){
 synchronized(monitor){
   ... //código lógico
 }
}

em outra você acessa esse monitor e também realiza um sincronismo


public void operacaoB{
 synchronized(monitor){
  ... // código lógico
 }
}

de forma que somente uma das operações ocorreão ao mesmo tempo
Mas como eu disse existem diveeeeeeeeeeeeeras maneiras até mesmo mais práticas e seguras de implementar um sincronismo de threads.
Esssa que citei é a mais simples.

Lembrando que você precisa manter o mesmo monitor para o mesmo contexto, porque assim você garante sincronismo de operações em cima de um único usuário.

Para uma aplicação web então esse monitor deve estar presente(vivo) no escopo de aplicação. Dae dessa forma apenas um usuário poderá executar a operação.
Seria isso?
Eu poderia criar esse monitor e colocá-lo no escopo da aplicação e utilizá-lo como chave do synchronized.
Obrigado pela ajuda.

Na verdade você teria esse monitor com escopo de sessão.

Mas se for escopo de sessão, como vou compartilhar a mesma instância do monitor entre as sessões?
Deixa eu ver se estou entendendo. Vamos supor que eu tenha 30 usuários simúltâneos, para esses 30 usuários eu devo ter apenas uma instância desse monitor, certo?
Se eu tiver que compartilhar o monitor entre todas as sessões, não seria então do contexto da aplicação?

O que eu quero é ter apenas um usuário realizando a operação. O exemplo que dei foi ilustrativo, apenas criei um cenário e, acho que ele gerou algumas dúvidas, mas eu quero poder realizar apenas uma operação por usuário, ou seja, se tiver 30 usuários simultâneo, apenas um terá o bloco sincronizado. Para isso o meu monitor deve estar no escopo da aplicação, certo?
Porque dessa forma eu teria apenas uma instância do monitor e garantiria que apenas um usuário estaria de posse do bloco sincronizado. Seria essa a idéia do monitor?
Desculpe incomodar com essas dúvidas, mas preciso realmente saber como implementar essa questão.
Abraço. DTA!

Bom agora não sei se sou eu que entendi bem, mas vamos lá.

A idéia deste monitor seria garantir que não fosse existir mais de uma operação que envolvesse saldo em cima de 1 usuário ao mesmo tempo.
/
Isso foi o que eu entendi.

Então se você quer garantir sincronismo de mais de 1 thread pra bloquear operações de 1 usuário então você terá 1 monitor por sessão. É um controle por um usuário e não 1 para vários.

:slight_smile: Não é isso?

Ok. Vamos esquecer então o cenário do saldo.
A minha dúvida é. Com a idéia do monitor que vc mencinou, eu quero ter apenas uma operação por Thread. Vamos supor que essa operação seja a de buscar o último id de uma determinada tabela e que tenhamos 30 usuários simultaneo. Como eu poderia utilizar a idéia do monitor para solucionar essa situação?

[code]
public Integer getMaxId() {

synchronized( minha_chave) {
// recupera a ultima chave para depois incrementar
}[/code]

E vamos supor que esses 30 usuários estão tentando fazer o insert de um registro e estão querendo pegar o ultimo id para poder incrementar( vamos supor que eu não esteja utilizando o auto_increment do mysql por exemplo). Como poderei fazer com que apenas uma Thread esteja execuntado o getMaxId de forma que os dados não fiquem corrompidos, ou seja, eu quero que o usuário 01 pegue o getMaxId 1, o usuarío 02 o getMaxId 2 e assim por diante.
O exemplo que dei do saque deu a entender que seria para aquele usuário. Acho que a minha dúvida é mais simples. Eu preciso de apenas uma Thread executando a operação.

A minha chave utilizada no bloco synchronized para esse caso que descreví deve ser algum objeto que esteja vivo durante toda a aplicação, ñao seria isso? Ou teria alguma outra solução para esse problema?
Abraço.

[quote=jhow360]Ok. Vamos esquecer então o cenário do saldo.
A minha dúvida é. Com a idéia do monitor que vc mencinou, eu quero ter apenas uma operação por Thread. Vamos supor que essa operação seja a de buscar o último id de uma determinada tabela e que tenhamos 30 usuários simultaneo. Como eu poderia utilizar a idéia do monitor para solucionar essa situação?

[code]
public Integer getMaxId() {

synchronized( minha_chave) {
// recupera a ultima chave para depois incrementar
}[/code]

E vamos supor que esses 30 usuários estão tentando fazer o insert de um registro e estão querendo pegar o ultimo id para poder incrementar( vamos supor que eu não esteja utilizando o auto_increment do mysql por exemplo). Como poderei fazer com que apenas uma Thread esteja execuntado o getMaxId de forma que os dados não fiquem corrompidos, ou seja, eu quero que o usuário 01 pegue o getMaxId 1, o usuarío 02 o getMaxId 2 e assim por diante.
O exemplo que dei do saque deu a entender que seria para aquele usuário. Acho que a minha dúvida é mais simples. Eu preciso de apenas uma Thread executando a operação.

A minha chave utilizada no bloco synchronized para esse caso que descreví deve ser algum objeto que esteja vivo durante toda a aplicação, ñao seria isso? Ou teria alguma outra solução para esse problema?
Abraço.
[/quote]

Olha no caso do saldo eu falei que seria de sessão pensando em sessão = usuário. O que muda de um caso para o outro é sua necessidade, porque o conceito mesmo no fim das contas é o mesmo, você utiliza o sincronismo para garantir operações thread/safe, ou seja, enquanto um mexe ninguém rela.

É a mesma coisa que querer definir como fazer um diagrama de classes ou diagrama de casos de uso, isso é impossível. O que pode ser feito é explicar como aplicar a regra mas como deve ser feito, não.

Portanto agora vai da sua imaginação e solução para algum problema. Se você quer garantir que dois métodos sejam executados sincronizadamente por várias threads então você PODE utilizar um monitor, agora se você quer que apenas um método seja executado sincronizadamente por várias threads então você coloca na assinatura do método “synchronized”, exemplo:

public synchronized int getNextId(){
    return currentId++;
}

A sua dúvida no caso era entender qual o escopo de um monitor, então pense quem vai acessar o monitor.
Se o seu monitor controla operações comuns para vários contextos então ele terá um escopo maior e vice-versa.

public void addSomething(){   
       int id = getNextId();
       ...
}

Neste caso se você utiliza esse ID para todos contextos possíveis em sua aplicação então sim ela é de escopo de aplicação, senão varia de sua necessidade.

Abraços

Correção, o que chamei de monitor aqui na verdade é um Mutex .

Abraços

Cara, agradeço sua ajuda. Agora ficou claro pra mim. Obrigado.
DTA!