多线程银行模拟

Multi Threading banking simulation

此刻我正在 java 中使用多线程,但我不确定它是如何工作的。我觉得我在互联网上看到的一个简单示例中理解了这一点但不知何故,我不明白这是如何在我从互联网上找到并修改的银行模拟应用程序中工作的。

这是我拥有的:

人class:

package threadsproject;

public class Person {

    private String name;

    public Person(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }

    public void setName(String name){
        this.name = name;
    }
}

帐户 class:

package threadsproject;

public class Account {

    public static int balance;
    public static Account acc;
    private static Person p;

    public static int getBal(){
        return balance;
    }

    public void setBal(int bal){
        Account.balance = bal;
    }

    public static Account getAcc(Person p){
        if(acc == null){
            acc = new Account();
        }
        Account.p = p;
        return acc;

    }

    public synchronized void deposit(int val){
        try{

            if(val > 0){
                System.out.println("Person "+p.getName()+" is making a deposit.");
                try{
                    Thread.sleep(500);
                }catch(Exception e){}
                balance = balance + val;
                System.out.println("Person "+p.getName()+" completed the deposit.");
            }else{
                System.out.println("Can't deposit.");
            }
            System.out.println("Person "+p.getName()+" deposited "+val);

        }catch(Exception e){}
    }

    public synchronized void withdraw(int val){
        try{

            if(balance >= val){
                System.out.println("Person "+p.getName()+" is making a withdraw.");
                try{
                    Thread.sleep(500);
                }catch(Exception e){}
                balance = balance - val;
                System.out.println("Person "+p.getName()+" completed the withdraw.");
            }else{
                System.out.println("Can't withdraw.");
            }
            System.out.println("Person "+p.getName()+" withdrew "+val);

        }catch(Exception e){}
    }

}

线程 Class:

package threadsproject;

import java.util.Scanner;

public class BankThread extends Thread implements Runnable{

    private Person p;

    public BankThread(Person p){
        this.p = p;
    }

    public void run(){
        for (int i = 0; i < 3; i++) {
            try {
                Account acc = Account.getAcc(p);
                Scanner s = new Scanner(System.in);
                System.out.println("Enter deposit ammount:");
                int dep = s.nextInt();
                acc.deposit(dep);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ex) { }

                System.out.println("Enter withdrawal ammount:");
                int with = s.nextInt();
                if(with > Account.getBal()){
                    System.out.println("You don't have enough funds.");
                }else{
                    acc.withdraw(with);
                }
                System.out.println("Final balance: "+Account.getBal());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub

        Person p1 = new Person("Person1");
        Person p2 = new Person("Person2");
        Person p3 = new Person("Person3");
        BankThread bt1 = new BankThread(p1);
        bt1.start();
        bt1.join();
        BankThread bt2 = new BankThread(p2);
        bt2.start();
        bt2.join();
        BankThread bt3 = new BankThread(p3);
        bt3.start();
        bt3.join();
    }

}

正如我提到的,这是我找到并修改的示例。这有效但我认为不正确。在线程 class 中,for 循环执行每个线程的代码 3 次。 我遇到的另一个问题是每个线程的帐户余额保持不变。因此,如果我的第一个线程的最终余额为 100,则第二个线程的初始余额相同,余额为 100,而不是从 0 开始。 如果我有不同的对象,它应该从 0 开始吧?

这是截图。

您描述的场景反映了您帐户 class 中 static 成员字段的用法。关键字 static 表示字段不再是对象边界的,因为它们是 class 边界的。因此,您的 Account 对象的每个实例都将在其任何实例上具有相同的 static 字段。

要修复它,您必须删除静态字段

 public static int balance;
 public static Account acc;
 private static Person p;

首先,正如评论中提到的那样,帐户 class 的名称是错误的。静态字段意味着该字段是 class 依赖的,而不是对象(class 的实例)依赖的。因此,您将在应用程序之间共享这些静态字段,这可以成为多线程的一个很好的例子。

每个线程执行 3 次 For 循环,因为它的目的是

for (int i = 0; i < 3; i++) {

它将在 i=0、i=1 和 i=2 时被调用

如果您想使用共享资源来玩多线程,我的建议是将帐户 class 的名称更改为 FamilyAccount,将 Person 更改为 FamilyMember,并将其视为家庭成员的共享帐户。拥有一个帐户将有更多逻辑,然后您可以使用多线程并检查例如每个成员是否看到实际金额。

如果你将删除静态字段,我认为它在多线程的情况下没有任何意义。如果每个人都有一个帐户,并且他们作为一个线程工作,则不需要同步。

此外,您的帐户 class 是 Singleton 的奇怪情况,其中有 public 构造函数和 getAcc 方法,它们总是 return class 的相同实例。

我鼓励您查看和阅读有关事务和单例的内容,以便更好地理解案例。