private int saldo = 50;
public int getSaldo(){
return saldo;
}
public void saque(int n){
saldo -= n;
}
}
public class Teste implements Runnable {
private Conta c = new Conta();
public void run() {
for (int i = 0; i < 5; i++) {
sacar(10);
}
}
public static void main(String[] args) {
Teste t = new Teste();
Thread one = new Thread(t);
Thread two = new Thread(t);
Thread three = new Thread(t);
one.setName("Joao");
two.setName("Maria");
three.setName("Pedro");
one.start();
two.start();
three.start();
}
private synchronized void sacar(int n) {
if (c.getSaldo() >= n) {
c.saque(n);
System.out.println(Thread.currentThread().getName() + " sacou: "
+ n + " reais " + "saldo em conta de: " + c.getSaldo()
+ " reais");
try {
Thread.sleep(500);
} catch (Exception e) {}
} else {
System.out.println("Sem saldo para o saque de "
+ Thread.currentThread().getName() + " Saldo: "
+ c.getSaldo() + " reais");
}
}
}[/code]
No livro da Kathy fala que a palavra reservada syncronized funciona como um bloqueio, e quando o Thread é suspenso ele mantém o bloqueio para que outros Threads não possam utilizar aquele método marcado como syncronized.
Só que testando esse código acima eu consegui a seguinte saída:
Joao sacou: 10 reais saldo em conta de: 40 reais
Joao sacou: 10 reais saldo em conta de: 30 reais
Maria sacou: 10 reais saldo em conta de: 20 reais
Maria sacou: 10 reais saldo em conta de: 10 reais
Maria sacou: 10 reais saldo em conta de: 0 reais
Sem saldo para o saque de Pedro Saldo: 0 reais
Sem saldo para o saque de Pedro Saldo: 0 reais
Sem saldo para o saque de Pedro Saldo: 0 reais
Sem saldo para o saque de Pedro Saldo: 0 reais
Sem saldo para o saque de Pedro Saldo: 0 reais
Sem saldo para o saque de Maria Saldo: 0 reais
Sem saldo para o saque de Maria Saldo: 0 reais
Sem saldo para o saque de Joao Saldo: 0 reais
Sem saldo para o saque de Joao Saldo: 0 reais
Sem saldo para o saque de Joao Saldo: 0 reais
A Maria pulou a vez do João antes que ele terminasse de sacar todo o dinheiro, existe alguma coisa errada?
Abraço
Editado:
Será que quando o João sai da suspensão o método é liberado novamente e o agendador decide quem executa ele primeiro?
Também estou estudando para a prova, a parte de Threads é bem complicada, achei esse capítulo meio confuso no livro da Kathy.
Sobre o seu código, o método sincronizado é o sacar(), ou seja, ele só pode ser utilizado por um Thread por vez, mas isso não garante que o primeiro Thread vai fazer todas as chamadas a esse método antes de outro Thread chamá-lo, exatamente o que você comentou no fim da sua mensagem.
O pessoal do forum pode ajudar com mais dicas/explicações, creio para fazer o que você queria, você deve colocar o código do método run() como sincronizado, testei aqui e deu certo.
O pessoal do forum pode ajudar com mais dicas/explicações, creio para fazer o que você queria, você deve colocar o código do método run() como sincronizado, testei aqui e deu certo.
[/quote]
Kra funcionou colocando no método run(), mas será que essa é a melhor forma sincronizando o método run()? pq no livro o método run() não está sincronizado, pelo menos nos exemplos que eu vi até agora!
Creio que não tem problema. Outra opção é colocar o código do método dentro de um bloco sincronizado:
public void run() {
synchronized (this){
for (int i = 0; i < 5; i++) {
sacar(10);
}
}
}
Mas no final o resultado é o mesmo.
Esse exemplo é mais para treinarmos para a prova, na prática não vejo muita aplicação para isso, já que tudo será executado como um Thread só, concorda? Já que o run() está sincronizado, e estamos trabalhando sobre a mesma instância da classe nas Threads, vai dar na mesma se você chamasse o método run() diretamente, 3 vezes. Um vai executar depois do outro.
A diferença é que não sabemos (da forma atual, com os Threads) qual será executado (apesar de ter grandes chances de seguir a ordem colocada no código).
Se você colocar no run, você irá forçar que um for rode depois do outro. Ou seja, vai serializar duas threads. Aí, pergunte-se, para que criar threads, se vou rodar um código depois do outro?
Obviamente, essa não é a melhor abordagem, caso você queira uma aplicação com execução paralela.
Estou respondendo sua pergunta um pouco atrasado… mas é bom até para mim que tb estou estudando java, treinar as respostas.
O seu programa não roda na sequencia correta pq o agendador da maquina virtual java, não garante que
os programas rodarão em uma sequencia correta.
Não é possível prever qual será a regra pela qual o agendador, que as vezes é o agendador do sistema operacional
subjacente. O que o agendador pode garantir é que o seu thread rodará até concluir o método run(), porém sem uma
sequencia definida… a não ser que vc defina alguma regra no seu próprio software para isso
Funciona como bloqueio sim, imagina se 2 threads (Joao e Maria) entrassem no método ao mesmo tempo poderia haver uma inconsistência nos dados, é muito provável que acontecesse isto aqui:
Joao sacou: 10 reais saldo em conta de: 0 reais
Maria sacou: 10 reais saldo em conta de: -10 reais
O pessoal do forum pode ajudar com mais dicas/explicações, creio para fazer o que você queria, você deve colocar o código do método run() como sincronizado, testei aqui e deu certo.
[/quote]
Kra funcionou colocando no método run(), mas será que essa é a melhor forma sincronizando o método run()? pq no livro o método run() não está sincronizado, pelo menos nos exemplos que eu vi até agora!
Valeu[/quote]
na verdade não faz sentido algum vc sincronizar o método run…