Dúvida com Synchronized

4 respostas
T

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
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!");
				}
			}
		}
	}

}
NumeroManage.java
import java.lang.Math;
public class NumeroManage implements Runnable{
	private double numeroTmp;
	public String name;
	private GuardaNumero gN = null;
private volatile Thread thread;
	public NumeroManage(String name, GuardaNumero gN){
		this.gN = gN;
		thread = new Thread(this, name);
		this.name = name;
		thread.start();
	}
	public void run(){
		while (true){
			adicione();
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	public void adicione(){
		gN.setNumero(gN.getNumero()+(Math.random()*5000));
		this.numeroTmp = gN.getNumero();
	}
	public synchronized double retire(){
		return this.numeroTmp;
	}
}
GuardaNumero.java
public final class GuardaNumero {
	private double numero;
	/**
	 * @return the numero
	 */
	public double getNumero() {
		return numero;
	}
	/**
	 * @param numero the numero to set
	 */
	public synchronized void setNumero(double numero) {
		this.numero = numero;
	}
}

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.

4 Respostas

P

mensagem dupla

P

Posso estar errado, mas meu palpite ta aqui:

TesteThread.java

GuardaNumero gN = new GuardaNumero();
...
NumeroManage nTmp;
...
nTmp.adicione(); 
if (gN.getNumero() != nTmp.retire())

NumeroManage.java

private GuardaNumero gN = null;
...
   public void adicione(){ 
      gN.setNumero(gN.getNumero()+(Math.random()*5000)); 
      this.numeroTmp = gN.getNumero(); 
   } 
   public synchronized double retire(){ 
      return this.numeroTmp; 
   }

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.

L

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 {

	int i = 0;

	synchronized void metodo() {
		System.out.println("Thread: " + Thread.currentThread() + " - valor de i: " + i++);
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
		}
		System.out.println("-- Saindo do método");
	}

	public void run() {
		while (true) {
			metodo();
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
			}			
		}
	}

	public static void main(String[] args) {
		Runnable r = new TesteThread();
		new Thread(r).start();
		new Thread(r).start();
	}
}

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!

T

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…

Criado 12 de julho de 2007
Ultima resposta 13 de jul. de 2007
Respostas 4
Participantes 3