Dúvida com Synchronized

Olá Pessoal,

Me encontro com uma dúvida quanto ao modificador Synchronized, talvez eu esteja errando na aplicação, mas fiz um teste aqui e realmente não funcionou, vou colocar os códigos para vocês verem se existe algo errado (que deve existir).
nesse código eu ativo 3 threads para modificar o valor de um objeto e então eu pego o valor modificado junto com o valor da thread para saber se os valores são iguais, teoricamente, pelo uso do synchronized deveria ser, mas não tá sendo… ai vai os códigos:

TesteThread.java

[code]import java.util.ArrayList;
public class TesteThread {
public static void main(String[] args) {
GuardaNumero gN = new GuardaNumero();
ArrayList<NumeroManage> ns = new ArrayList<NumeroManage>();
for (int x = 0; x < 5; x++){
ns.add(new NumeroManage(("n"+x), gN));
}
NumeroManage nTmp;
while (true){
for (int i = 0; i < 3; i++){
nTmp = ns.get(i);
nTmp.adicione();
// System.out.println(nTmp.name);
if (gN.getNumero() != nTmp.retire()){
System.out.println("Diferente!");
}
}
}
}

}
[/code]

NumeroManage.java

import java.lang.Math; public class NumeroManage implements Runnable&#123; private double numeroTmp; public String name; private GuardaNumero gN = null; private volatile Thread thread; public NumeroManage&#40;String name, GuardaNumero gN&#41;&#123; this.gN = gN; thread = new Thread&#40;this, name&#41;; this.name = name; thread.start&#40;&#41;; &#125; public void run&#40;&#41;&#123; while &#40;true&#41;&#123; adicione&#40;&#41;; try &#123; Thread.sleep&#40;1&#41;; &#125; catch &#40;InterruptedException e&#41; &#123; e.printStackTrace&#40;&#41;; &#125; &#125; &#125; public void adicione&#40;&#41;&#123; gN.setNumero&#40;gN.getNumero&#40;&#41;+&#40;Math.random&#40;&#41;*5000&#41;&#41;; this.numeroTmp = gN.getNumero&#40;&#41;; &#125; public synchronized double retire&#40;&#41;&#123; return this.numeroTmp; &#125; &#125;

GuardaNumero.java

public final class GuardaNumero &#123;
	private double numero;
	/**
	 * @return the numero
	 */
	public double getNumero&#40;&#41; &#123;
		return numero;
	&#125;
	/**
	 * @param numero the numero to set
	 */
	public synchronized void setNumero&#40;double numero&#41; &#123;
		this.numero = numero;
	&#125;
&#125;

Bom, é isso, se vocês rodarem o código vocês veram que o retorno “Diferente!” acontece com uma grande frequência, o que mostra que o synchronized não está tendo efeito :(!

Valeu e um forte abraço a todos.

mensagem dupla

Posso estar errado, mas meu palpite ta aqui:

TesteThread.java

GuardaNumero gN = new GuardaNumero&#40;&#41;;
...
NumeroManage nTmp;
...
nTmp.adicione&#40;&#41;; 
if &#40;gN.getNumero&#40;&#41; != nTmp.retire&#40;&#41;&#41;

NumeroManage.java

private GuardaNumero gN = null;
...
   public void adicione&#40;&#41;&#123; 
      gN.setNumero&#40;gN.getNumero&#40;&#41;+&#40;Math.random&#40;&#41;*5000&#41;&#41;; 
      this.numeroTmp = gN.getNumero&#40;&#41;; 
   &#125; 
   public synchronized double retire&#40;&#41;&#123; 
      return this.numeroTmp; 
   &#125; 

Vc queria, na verdade, comparar o gn.getnumero() que ta dentro do nTmp, mas na verdade vc ta comparando o gN.getnumero() da propria classe TesteThread com ntmp.retire()… ou seja, vc ta comparando um valor que foi incrementado com um numero randomico com o valor antigo…

Corrijam-me se estiver errado,
espero estar certo hehe.

Diz ai para que vc acha que é o synchronized, pode ser que vc esteja com uma noção errada. O synchronized serve para impedir que duas threads executem o mesmo bloco juntas… mas no seu exemplo vc se quer criou uma nova thread, então não há acesso concorrente a nada…

da uma olhada nesse exemplo:

public class TesteThread implements Runnable &#123;

	int i = 0;

	synchronized void metodo&#40;&#41; &#123;
		System.out.println&#40;&quot;Thread&#58; &quot; + Thread.currentThread&#40;&#41; + &quot; - valor de i&#58; &quot; + i++&#41;;
		try &#123;
			Thread.sleep&#40;1000&#41;;
		&#125; catch &#40;InterruptedException e&#41; &#123;
		&#125;
		System.out.println&#40;&quot;-- Saindo do método&quot;&#41;;
	&#125;

	public void run&#40;&#41; &#123;
		while &#40;true&#41; &#123;
			metodo&#40;&#41;;
			try &#123;
				Thread.sleep&#40;100&#41;;
			&#125; catch &#40;InterruptedException e&#41; &#123;
			&#125;			
		&#125;
	&#125;

	public static void main&#40;String&#91;&#93; args&#41; &#123;
		Runnable r = new TesteThread&#40;&#41;;
		new Thread&#40;r&#41;.start&#40;&#41;;
		new Thread&#40;r&#41;.start&#40;&#41;;
	&#125;
&#125;

São duas threads agindo sobre um unico objeto TesteThread, ou seja, esse método esta sendo usado por duas threads, eu não quero que as duas threads acessem o método “metodo” dele ao mesmo tempo então coloco o metodo como synchronized… vc vai ver que só quando uma thread termina de executar o método que a outra vai poder acessar… ai testa tirar o synchronized fora, vc vai ver que as duas threads vão executar o método “ao mesmo tempo”…

Não usei seu código porque realmente eu não entendi o que vc queria fazer ali hehe mas espero ter ajudado.

flw!

luBS, obrigado pela explicação, ela esclareceu muito. A maioria dos materiais que encontro acerca a de synchronized vem com uma abordagem branda ao assunto. Pude entender seu exemplo, mas ainda não entende direito o pleno uso do synchronized. Eu quero supor um caso real e saber se o synchronized se aplica nele:
Supondo que uma conta poupança não possa nunca ficar negativa, e você tem uma condicional (if) que faz essa verificação, porêm, a conta começa com R$100,00 e você faz vários (1000+) pedido de saque ao mesmo tempo para remover justamente esses R$100,00… É possível que após a verificação de um desses saques e a condicional seja satisfeita, os outros passem e realizem o restante dos saques, deixando a conta negativa?
Como eu poderia usar o synchronized nessa situação para evitar que isso ocorra?
Lembro que algo semelhante ocorria em sites que vinham com bloqueio para o botão direito do mouse, se você realizasse 2 cliques muito rápidos, o sistema deixava passar um dos cliques e você tinha acesso ao menu, mesmo o script rodando no client…