银行账户/用户申请:多线程和同步

时间:2018-01-16 14:07:46

标签: java multithreading synchronization thread-synchronization

对于我目前的单一课程,我的意思是创建一个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);
}
}

2 个答案:

答案 0 :(得分:0)

您应该使用信号量来控制对关键部分的访问。我想每个用户都可以访问他们的getAccountInfo(),但是如果两个用户可以访问同一个银行帐户,其他方法(例如withdrawdeposist)应该有一定的控制权。

同样在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)

  

有关我如何改进此非同步版本的任何帮助

通常,当方法以getset开头时,该方法应分别返回或设置值。您的get方法仅打印到控制台。假设在赋值中没有明确说明行为,我会修改它们,以便它们返回名称中指示的值:

public double getAccountNumber() {
    return accountNo;
}

public double getAccountBalance() {
    return accountBalance;
}

您可以在从BankAccount实例中检索后打印出的详细信息。如果您愿意,可以将这些交互包装在某种BankingSession类中。

作业是否指定了如何处理可能导致负余额的交易?如果允许用户获得负余额,则depositwithdraw永远不会失败。但如果他们不能,你应该表明交易是否成功。有几种方法可以做到这一点。一种方法是将void方法的返回类型从boolean更改为withdraw,只有在提取成功完成后才返回true(意味着有足够的资金可用) 。否则,请返回false。如果事务无法完成,另一种选择是抛出异常(如自定义InsufficientFundsException)。

  

有关如何同步它的任何帮助

只有两种方法可以修改银行帐户的状态:withdrawdeposit。由于您彼此独立地呼叫这些(每次存款或取款是一项独立的行动),您只需要确保一次只能发生其中一种。将synchronized关键字添加到方法声明中就足够了,例如:

public synchronized void deposit(double value) { ... }
public synchronized void withdraw(double value) { ... }