【问题标题】:Handling Concurrent requests for a Bank Transaction in the real world处理现实世界中银行交易的并发请求
【发布时间】:2016-02-18 17:03:36
【问题描述】:

我试图在一个帐户上执行多个存款/取款交易的经典银行余额问题。

我已经同步了账户类中的两个方法,只有加入所有线程(等待执行完成),执行结束时账户余额为500。

所以我正在考虑一个现实世界的场景,其中每个请求都会产生一个新线程来执行事务并返回余额。每次报告的余额是否不正确,因为有其他线程在同一个帐户上运行?

代码如下:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;


 class Account {

    private int balance = 0;


    Account(int bal){
        this.balance =bal;
    }

    public int getBal() {
        return balance;
    }


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

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

public class TransactionManagerNaiveSync implements Runnable {

    Account account;

    public TransactionManagerNaiveSync(Account a){
     this.account = a;
    }
    public static void main(String[] args) {

        long start = System.currentTimeMillis();
         Account a1 = new Account(500);
        TransactionManagerNaiveSync t1 = new TransactionManagerNaiveSync(a1);

        List<Thread> thread = new ArrayList<Thread>();
        for(int i=0;i < 300;i++) thread.add(new Thread(t1));
        for(int i=0;i < 300;i++) thread.get(i).start();
        for(int i=0;i < 300;i++){
            try {
                thread.get(i).join();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        long end = System.currentTimeMillis();
        System.out.println(" Account Balance in the end : "+ a1.getBal());
        System.out.println(" Time Taken : "+(end - start));
    }



    @Override
    public void run() {

        //for(int i=0;i < 100;i++)
        //{
            account.deposit(10);
            System.out.println(""+Thread.currentThread().getId()+" Account Balance after deposit : "+account.getBal());
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            account.withdraw(10);
            System.out.println(""+Thread.currentThread().getId()+" Account Balance after withdrawal : "+account.getBal());
        //}

    }

}

【问题讨论】:

  • 如果 (a) 有一条规则不允许任何线程看到负余额,并且 (b) 线程会先取款,然后暂停,然后存钱。
  • 是的,正确..在我的情况下会更有趣或更令人困惑:D。我只是想知道这在现实世界中是如何工作的。

标签: java multithreading concurrency


【解决方案1】:

余额可能不正确,因为您没有同步 Account.getBal(),这意味着您可能无法获得最新值,因为内存可见性保证不可用于对由多个线程更新的变量进行非同步访问.

只需标记方法synchronized

如果您将余额存储为AtomicInteger 而不是int,也会更容易(而且几乎肯定会更高效),因为那时您根本不需要synchronize

【讨论】:

  • 是的,确实如此,但我必须在请求级别进行同步,对吗?不仅仅是帐户级别,因为余额需要锁定在请求级别?
【解决方案2】:

我已经同步了这两个方法...

所以我正在考虑一个真实世界的场景......每次报告的余额是否不正确,因为有其他线程在同一个帐户上运行?

嗯,这取决于您所说的“正确的平衡”是什么意思。如果其他线程可以在您请求它的时间和您打印它的时间之间改变它,那么正确的平衡是什么

在多线程环境中,关于“正确”含义的不同想法被称为一致性模型

一种非常容易理解的一致性模型称为静态一致性。如果你的程序是静态一致的,这意味着当所有线程同时空闲时,平衡在任何时​​候都是正确的(这里,“空闲”意味着做任何不影响平衡的事情)。这很容易定义,但测试起来可能很棘手:如果没有这样的时刻发生怎么办?

另一种一致性模型称为线性化。线性化的简单定义是,如果余额每次都“正确”,并且在准确的瞬间,当你的一个线程释放用于保护余额的锁时,你的程序是线性化的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-29
    • 2021-08-14
    • 1970-01-01
    • 2023-03-26
    • 2016-07-25
    • 1970-01-01
    • 2013-10-24
    • 2010-11-28
    相关资源
    最近更新 更多