对于我目前的单一课程,我的意思是创建一个Java控制台应用程序,模拟创建共享银行帐户,最多4个用户可以同时访问。利用我在网上找到的所有资源和其他多线程应用程序,我能够将当前代码挂钩。
这是心态 - 每个用户都应该有平等的银行账户访问权限,没有延迟,死锁,等待等等。每次执行的交易(提款和存款)都应该更新到银行余额并记录下来。要为每个用户执行的特定事务存储在数组列表中。
我要创建应用程序的不同步版本和同步版本。我通过创建4个类来实现它--BankAccount(银行帐户),BankTester(运行主应用程序的测试器类),User(用户)和UserThread(用户的线程类)。
我现在所拥有的是应用程序的非同步版本。关于我如何同步(并改进这个不同步版本)的任何帮助,它将有助于我现在多线程。谢谢你们。
这是我的代码。
BankAccount类:
public class BankAccount {
private long accountNo;
private double accountBalance;
public BankAccount() {
this.accountNo = 9876543210L;
this.accountBalance = 1980;
}
public void getAccountInfo() {
System.out.println("Account Number: " + accountNo);
System.out.println("Starting Account Balance: " + accountBalance);
}
public void getAccountBalance() {
System.out.println("Account Balance: " + accountBalance);
}
public void deposit(double value) {
accountBalance = (accountBalance + value);
System.out.println("Account Balance After Deposit: " + accountBalance);
}
public void withdraw(double value) {
accountBalance = (accountBalance + value);
System.out.println("Account Balance After Withdrawal: " + accountBalance);
}
}
BankTest课程:
import java.util.Scanner;
public class BankTest {
private static double[][] transactionList = {
{50, 10, -20, 10, -20, 20, 10, 50, -10, 10, -10, 50},
{20, 20, -20, 50, -20, 10, 50, 50, -20, 10, 10},
{50, 10, 10, -10, -10, 50, 20, -10, -20},
{50, 10, -20, 20, 10, -20}
};
private static BankAccount myAccount;
private static UserThread myUser1;
private static UserThread myUser2;
private static UserThread myUser3;
private static UserThread myUser4;
public static void main(String[] args) {
for (;;) {
System.out.println("<--------- Banking Menu ----------->");
System.out.println("1. Create Bank Account");
System.out.println("2. Create User");
System.out.println("3. Run Simulation");
System.out.println("4. Exit");
System.out.println("Enter choice: ");
Scanner in = new Scanner(System.in);
switch (in.nextInt()) {
case 1:
System.out.println("<--------- Create Bank Account ----------->");
myAccount = new BankAccount();
System.out.println("Bank Account Created!");
break;
case 2:
System.out.println("<--------- Create User ----------->");
System.out.println("1. User 1");
System.out.println("2. User 2");
System.out.println("3. User 3");
System.out.println("4. User 4");
userMenu();
break;
case 3:
myUser1.start();
myUser2.start();
myUser3.start();
myUser4.start();
break;
case 4:
System.out.println("Goodbye");
System.exit(0);
break;
default:
System.err.println("Unrecognized option");
break;
}
}
}
public static void userMenu() {
Scanner in = new Scanner(System.in);
switch (in.nextInt()) {
case 1:
System.out.println("<----- User 1 ------>");
User user1 = new User("Saul", "Goodman", myAccount, transactionList[0]);
myUser1 = new UserThread(user1, "User 1 Thread");
user1.getUserInfo();
break;
case 2:
System.out.println("<-------- User 2 ------->");
User user2 = new User("Walter", "White", myAccount, transactionList[1]);
myUser2 = new UserThread(user2, "User 2 Thread");
user2.getUserInfo();
break;
case 3:
System.out.println("<-------- User 3 ------->");
User user3 = new User("Jessie", "Pinkman", myAccount, transactionList[2]);
myUser3 = new UserThread(user3, "User 3 Thread");
user3.getUserInfo();
break;
case 4:
System.out.println("<-------- User 4 ------->");
User user4 = new User("Hank", "Schrader", myAccount, transactionList[3]);
myUser4 = new UserThread(user4, "User 4 Thread");
user4.getUserInfo();
break;
default:
System.err.println("Unrecognized option");
break;
}
}
public static void runSimulation(User u) {
double[] tList = u.getTransactionList();
BankAccount ba = u.getBankAccount();
for (int i = 0; i < tList.length; i++){
if(tList[i] < 0) {
ba.withdraw(tList[i]);
} else{
ba.deposit(tList[i]);
}
u.getName();
ba.getAccountBalance();
}
}
}
用户类:
public class User {
private String name;
private String surname;
private BankAccount bankAccount;
private double[] transactionList;
public User(String n, String s, BankAccount bA, double[] tL) {
this.name = n;
this.surname = s;
this.bankAccount = bA;
this.transactionList = tL;
}
public void getName() {
System.out.println("Name: " + this.name);
}
public double[] getTransactionList(){
return transactionList;
}
public void getSurname() {
System.out.println("Surname: " + this.surname);
}
public void getUserInfo() {
System.out.println("Full name: " + this.name + " " + this.surname);
}
public BankAccount getBankAccount() {
return bankAccount;
}
}
UserThread类:
public class UserThread extends Thread {
private User u;
public UserThread(User u, String name) {
super(name);
this.u = u;
}
@Override
public void run() {
BankTest.runSimulation(this.u);
}
}
答案 0 :(得分:0)
您应该使用信号量来控制对关键部分的访问。我想每个用户都可以访问他们的getAccountInfo()
,但是如果两个用户可以访问同一个银行帐户,其他方法(例如withdraw
或deposist
)应该有一定的控制权。
同样在getAccountInfo()
你有这个:
public void getAccountInfo() {
System.out.println("Account Number: " + accountBalance);
System.out.println("Starting Account Balance: " + accountBalance);
}
但应该是这样的:
public void getAccountInfo() {
System.out.println("Account Number: " + accountNo);
System.out.println("Starting Account Balance: " + accountBalance);
}
修改:
如果您只有一个用户访问银行帐户,则无需控制任何内容。但是,想象一下,在银行账户中我们有100美元的余额。如果两个用户在“同一时间”尝试withdraw
,则两者都将获得100美元。所以,你应该控制那种行为。使用semaphores
会对您有所帮助。
答案 1 :(得分:0)
有关我如何改进此非同步版本的任何帮助
通常,当方法以get
或set
开头时,该方法应分别返回或设置值。您的get
方法仅打印到控制台。假设在赋值中没有明确说明行为,我会修改它们,以便它们返回名称中指示的值:
public double getAccountNumber() {
return accountNo;
}
public double getAccountBalance() {
return accountBalance;
}
您可以在从BankAccount
实例中检索后打印出的详细信息。如果您愿意,可以将这些交互包装在某种BankingSession
类中。
作业是否指定了如何处理可能导致负余额的交易?如果允许用户获得负余额,则deposit
和withdraw
永远不会失败。但如果他们不能,你应该表明交易是否成功。有几种方法可以做到这一点。一种方法是将void
方法的返回类型从boolean
更改为withdraw
,只有在提取成功完成后才返回true
(意味着有足够的资金可用) 。否则,请返回false
。如果事务无法完成,另一种选择是抛出异常(如自定义InsufficientFundsException
)。
有关如何同步它的任何帮助
只有两种方法可以修改银行帐户的状态:withdraw
和deposit
。由于您彼此独立地呼叫这些(每次存款或取款是一项独立的行动),您只需要确保一次只能发生其中一种。将synchronized
关键字添加到方法声明中就足够了,例如:
public synchronized void deposit(double value) { ... }
public synchronized void withdraw(double value) { ... }