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{
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 :(!
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.
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.
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…