以下程序模拟了一个银行账户,两个线程分别进行存款和取款操作。运行结果可能不一定,因为该程序存在竞态条件。

public class BankAccount {
    private int balance;

    public BankAccount(int initialBalance) {
        balance = initialBalance;
    }

    public synchronized void deposit(int amount) {
        balance += amount;
    }

    public synchronized void withdraw(int amount) {
        balance -= amount;
    }

    public synchronized int getBalance() {
        return balance;
    }
}

public class Accountant implements Runnable {
    private BankAccount account;

    public Accountant(BankAccount account) {
        this.account = account;
    }

    public void run() {
        for (int i = 0; i < 10000; i++) {
            account.deposit(1);
        }
    }
}

public class Cashier implements Runnable {
    private BankAccount account;

    public Cashier(BankAccount account) {
        this.account = account;
    }

    public void run() {
        for (int i = 0; i < 10000; i++) {
            account.withdraw(1);
        }
    }
}

public class Bank {
    public static void main(String[] args) {
        BankAccount account = new BankAccount(10000);

        Thread t1 = new Thread(new Accountant(account));
        Thread t2 = new Thread(new Cashier(account));

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println('Final balance: ' + account.getBalance());
    }
}

在多线程环境下,两个线程同时访问同一个账户对象,一个线程在存钱,一个线程在取钱,可能会导致账户余额出现错误的情况。例如,如果账户余额为10000,线程1存入1元,线程2取出1元,如果两个操作不是原子操作,可能会出现线程1存入1元后,线程2还未来得及取出1元,此时账户余额为10001,但是线程2取出1元后,账户余额变为9999,导致账户余额出现错误。

因此,需要对存钱和取钱的方法进行同步,保证每次只有一个线程访问该对象,避免竞态条件的发生。在本例中,我们使用 synchronized 关键字对 depositwithdrawgetBalance 方法进行同步,保证了每次只有一个线程可以访问账户对象,从而避免了竞态条件的发生。

代码解读:

  • BankAccount 类代表银行账户,包含余额 balance 和存款 deposit、取款 withdraw、获取余额 getBalance 等方法。
  • Accountant 类代表存款线程,负责向账户存款。
  • Cashier 类代表取款线程,负责从账户取款。
  • Bank 类为主程序,创建账户、线程并启动线程。

关键点:

  • 竞态条件:多个线程同时访问共享资源,且操作结果依赖于线程执行顺序,导致最终结果不可预测的情况。
  • 同步:使用 synchronized 关键字对方法进行同步,保证同一时间只有一个线程可以访问该方法。
  • 原子操作:不可分割的操作,要么全部执行,要么全部不执行。

总结:

多线程编程中,竞态条件是常见的错误来源,使用同步机制可以有效地解决竞态条件问题,保证程序的正确性。

Java 多线程银行账户操作:竞态条件与同步解决方案

原文地址: https://www.cveoy.top/t/topic/jmjj 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录