我有以下java代码。这会给每个人带来不同的输出。我必须使用信号量和互斥量,但我不知道在哪里使用。我是多线程的新手,所以有人可以告诉我这个程序中的线程在哪里。我该怎么做才能获得一致的结果
Account.java
package banking;
public class Account {
final String accountHolder;
final String accountType;
double balance=0;
public Account(String name, String type,double credit) {
this.accountHolder = name;
this.accountType = type;
this.balance=credit;
}
public void deposit(double credit) {
balance += credit;
}
public void withdraw(double credit) {
balance -= credit;
}
public void addinterest(double rate) {
balance *= (100+rate)/100.0;
}
}
Banking.java
package banking;
public class Banking {
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws InterruptedException {
System.out.println("Application started");
Account savings = new Account("Pete","Super Saver",1000);
Account checking = new Account("Pete","Free Checking",1000);
System.out.println("\nBeginning of month");
System.out.println(savings.accountType + ":\t"+ savings.balance);
System.out.println(checking.accountType + ":\t"+ checking.balance);
System.out.println("Total before \t"+ (checking.balance+savings.balance));
Interest checkInterest = new Interest(checking, -10);
Interest saveInterest = new Interest(savings, 10);
Transfer transfer = new Transfer(savings,checking,100);
checkInterest.start();
saveInterest.start();
transfer.start();
Thread.sleep(520);
System.out.println("\nEnd of month");
System.out.println(savings.accountType + ":\t"+ savings.balance);
System.out.println(checking.accountType + ":\t"+ checking.balance);
System.out.println("Total after \t"+ (checking.balance+savings.balance));
System.out.println("Main thread finished");
}
}
Interest.java
package banking;
import java.util.logging.Level;
import java.util.logging.Logger;
class Interest extends java.lang.Thread {
final Account myAccount;
double myRate;
public Interest(Account account, double rate) {
this.myAccount=account;
this.myRate = rate;
setName("Interest");
}
@Override
public void run() {
System.out.println("Interest this month on "+ myAccount.accountType + ":\t" + myAccount.balance*myRate/100.0);
myAccount.addinterest(myRate);
//System.out.println(getName() + " to account " + myAccount.accountType + " successfully applied");
}
}
Transfer.java
package banking;
import java.util.logging.Level;
import java.util.logging.Logger;
class Transfer extends java.lang.Thread {
final Account myAccount1;
Account myAccount2;
double myAmount;
public Transfer(Account account1,Account account2, double amount) {
this.myAccount1=account1;
this.myAccount2=account2;
this.myAmount = amount;
setName("Transfer");
}
@Override
public void run() {
myAccount1.withdraw(myAmount);
myAccount2.deposit(myAmount);
System.out.println(getName() + " from " + myAccount1.accountType + " to " + myAccount2.accountType + " successfully applied");
}
}
请帮我解决这个问题。
答案 0 :(得分:2)
不需要信号量。只需在synchronized
类中的每个方法之前添加Account
。例如:
public synchronized void deposit(double credit) {
balance += credit;
}
[编辑]
当方法为synchronized
时,运行时环境保证如果多个线程在给定对象中调用相同的方法,则只执行其中一个,其他线程一直等到完成。然后执行另一个线程,依此类推。
[EDIT2]
另外,请勿直接访问Account
的数据成员。让他们private
并定义synchronized
getter和setter。程序中的真正问题在于传输操作:
myAccount1.withdraw(myAmount);
myAccount2.deposit(myAmount);
这种方式不是原子的。想象一下,例如,兴趣线程在执行中的这两行之前执行,而在另一行之间执行。您将获得不同的最终结果。要解决此问题,请将以下方法添加到Account
类:
public synchronized void transfer (Account to, double amount) {
this.withdraw (amount);
to.deposit(amount);
}
并通过此调用替换两行:
synchronized(myAccount2) {
myAccount1.transfer(myAccount2, myAmount);
}
在synchronized
方法的调用周围添加transfer
块的原因是您需要获取两个对象的两个锁才能执行传输。 synchronized(myAccount2)
获取myAccount2的锁定,transfer
的调用获取myAccount1的锁定,方法transfer
已同步。
[EDIT3]
您的计划中还存在一个概念性问题。您正在计算两个帐户的利益并在它们之间转移资金,所有这些都在并行线程中。因此,如果您首先转移资金然后计算利息,或者如果您首先计算利息然后转移资金,那么产生不同结果是正常的。尝试手工完成数学运算。如果您想对操作进行排序,请不要使用线程,只需按顺序调用方法
答案 1 :(得分:0)
您可以将thread.join()用于checkInterest和saveInterest。因此,当两个结束时,转移开始
checkInterest.start();
saveInterest.start();
checkInterest.join();
saveInterest.join();
transfer.start();