100个线程同时向一个银行账户中存入1元钱

下面的例子演示了100个线程同时向一个银行账户中存入1元钱,在没有使用同步机制和使用同步机制情况下的执行情况。

  • 银行账户类:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

/**

 * 银行账户

 * @author 骆昊

 *

 */

public class Account {

    private double balance;     // 账户余额

    /**

     * 存款

     * @param money 存入金额

     */

    public void deposit(double money) {

        double newBalance = balance + money;

        try {

            Thread.sleep(10);   // 模拟此业务需要一段处理时间

        }

        catch(InterruptedException ex) {

            ex.printStackTrace();

        }

        balance = newBalance;

    }

    /**

     * 获得账户余额

     */

    public double getBalance() {

        return balance;

    }

}

  • 存钱线程类:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

/**

 * 存钱线程

 * @author 骆昊

 *

 */

public class AddMoneyThread implements Runnable {

    private Account account;    // 存入账户

    private double money;       // 存入金额

    public AddMoneyThread(Account account, double money) {

        this.account = account;

        this.money = money;

    }

    @Override

    public void run() {

        account.deposit(money);

    }

}

  • 测试类:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class Test01 {

    public static void main(String[] args) {

        Account account = new Account();

        ExecutorService service = Executors.newFixedThreadPool(100);

        for(int i = 1; i <= 100; i++) {

            service.execute(new AddMoneyThread(account, 1));

        }

        service.shutdown();

        while(!service.isTerminated()) {}

        System.out.println("账户余额: " + account.getBalance());

    }

}

在没有同步的情况下,执行结果通常是显示账户余额在10元以下,出现这种状况的原因是,当一个线程A试图存入1元的时候,另外一个线程B也能够进入存款的方法中,线程B读取到的账户余额仍然是线程A存入1元钱之前的账户余额,因此也是在原来的余额0上面做了加1元的操作,同理线程C也会做类似的事情,所以最后100个线程执行结束时,本来期望账户余额为100元,但实际得到的通常在10元以下(很可能是1元哦)。解决这个问题的办法就是同步,当一个线程对银行账户存钱时,需要将此账户锁定,待其操作完成后才允许其他的线程进行操作,代码有如下几种调整方案:

  • 在银行账户的存款(deposit)方法上同步(synchronized)关键字

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

/**

 * 银行账户

 * @author 骆昊

 *

 */

public class Account {

    private double balance;     // 账户余额

    /**

     * 存款

     * @param money 存入金额

     */

    public synchronized void deposit(double money) {

        double newBalance = balance + money;

        try {

            Thread.sleep(10);   // 模拟此业务需要一段处理时间

        }

        catch(InterruptedException ex) {

            ex.printStackTrace();

        }

        balance = newBalance;

    }

    /**

     * 获得账户余额

     */

    public double getBalance() {

        return balance;

    }

}

  • 在线程调用存款方法时对银行账户进行同步

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

/**

 * 存钱线程

 * @author 骆昊

 *

 */

public class AddMoneyThread implements Runnable {

    private Account account;    // 存入账户

    private double money;       // 存入金额

    public AddMoneyThread(Account account, double money) {

        this.account = account;

        this.money = money;

    }

    @Override

    public void run() {

        synchronized (account) {

            account.deposit(money);

        }

    }

}

  • 通过Java 5显示的锁机制,为每个银行账户创建一个锁对象,在存款操作进行加锁和解锁的操作

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

/**

 * 银行账户

 *

 * @author 骆昊

 *

 */

public class Account {

    private Lock accountLock = new ReentrantLock();

    private double balance; // 账户余额

    /**

     * 存款

     *

     * @param money

     *            存入金额

     */

    public void deposit(double money) {

        accountLock.lock();

        try {

            double newBalance = balance + money;

            try {

                Thread.sleep(10); // 模拟此业务需要一段处理时间

            }

            catch (InterruptedException ex) {

                ex.printStackTrace();

            }

            balance = newBalance;

        }

        finally {

            accountLock.unlock();

        }

    }

    /**

     * 获得账户余额

     */

    public double getBalance() {

        return balance;

    }

}

按照上述三种方式对代码进行修改后,重写执行测试代码Test01,将看到最终的账户余额为100元。当然也可以使用Semaphore或CountdownLatch来实现同步

原文地址:https://www.cnblogs.com/duanqiao123/p/9196722.html

时间: 2024-08-09 21:33:01

100个线程同时向一个银行账户中存入1元钱的相关文章

定义一个银行账户

//定义一个银行账户类.银行账户包含两部分数据:账户余额和利率rate.其中余额用两个整型值来表示:一个代表美元accountDollars,一个代表美分accountCents.即该类的数据成员有3个(accountDollars,accountCents,rate).注意:负的账户余额用负的dollars和负的cents表示,例如-$4.50将accountDollars设置为-4,将accountCents设置为-50.//1)        用户可以认为账户的余额是一个double类型表

个人银行账户管理程序

这个程序是一个银行账户管理的程序,是用C++来实现程序功能的,该程序包含六个文件,其中有date.h头文件 是日期类的头文件,date.cpp是日期类的实现文件,accumulator.h是按日将数值累加的accumulator类的头文件, account.h是各个储蓄账户类定义的头文件,account.cpp是各个储蓄账户类的实现文件,还有就是主函数文件.该 程序包含了增加账户功能.存款功能.取款功能.查询账户信息功能.改变日期功能.进入下个月的处理功能,最 后是退出程序.下面是各个程序文件:

申请Payoneer美国万事达信用卡,可获得一个美国虚拟银行账户,立即注册可得25美元

申请Payoneer美国万事达信用卡,可获得一个美国虚拟银行账户,可以在国内任意一个支持万事达的ATM.POS机上取现和刷卡消费.Payoneer可以网上购物,购买国外的产品,对我们有一个好处就是利用Payoneer美国信用卡的身份,购买Godaddy一些只要求美国信用卡付款的域名,或者向外国公司收款.此卡无透支功能.立即注册可得25美元:http://share.payoneer-affiliates.com/v2/share/6114410446805048501

Java实验-课程设计报告一:个人银行账户管理系统SavingAccountManageSystem-具体文档+源码

课程设计报告一:个人银行账户管理系统 此文档及源码仅供参考 不得直接复制使用 author: [xxxxxxxxx xx xxxx] date: "2019-04-12" 作 者:31415926535x 出 处:https://www.cnblogs.com/31415926535x/p/10697659.html 版权声明:署名 - 非商业性使用 - 禁止演绎,协议普通文本 | 协议法律文本. 不建议直接复制文档.源码,没意义,这东西还是自己手敲一下才能涨经验 项目所有的内容都已上

.NET一个线程更新另一个线程的UI(两种实现方法及若干简化)

Winform中的控件是绑定到特定的线程的(一般是主线程),这意味着从另一个线程更新主线程的控件不能直接调用该控件的成员. 控件绑定到特定的线程这个概念如下: 为了从另一个线程更新主线程的Windows Form控件,可用的方法有: 首先用一个简单的程序来示例,这个程序的功能是:在Winfrom窗体上,通过多线程用label显示时间.给出下面的两种实现方式 1.结合使用特定控件的如下成员 InvokeRequired属性:返回一个bool值,指示调用者在不同的线程上调用控件时是否必须使用Invo

使用SQL-Server创建一个银行数据管理系统Ⅰ

使用SQL-Server创建一个银行数据管理系统Ⅰ 作者声明: 刚开始写博客,难免有些不足的地方,再就是本人初涉软件开发这一行业,是个不折不扣的小白,文章中肯定也会出现一些错误的地方,希望发现错误的朋友们可以及时的指出来,不足的地方还请各路大神们多多指教,以便本人参考和学习,多谢. 首先,要创建一个完整的数据管理系统,不是一蹴而就的,一定要要一步一步的来,不断完善,最终方能达到自己想要的结果,所以兔子在这里也是一点一点分步来做的. 创建数据库,数据库属性在这里用的是默认(不推荐使用这种偷懒的做法

银行账户管理系统详细设计说明书

银行账户管理系统详细设计说明书 第一部分  引言 1.1  编写目的 本说明对会议室管理系统项目的各模块.页面.脚本分别进行了实现层面上的要求和说明. 软件开发小组的产品实现成员应该阅读和参考本说明进行代码的编写.测试. 1.2  背景 说明: A. 软件系统的名称:银行账户管理系统 B. 任务提出者:内蒙古大学计算机学院 开发者:魏晓蕾.宋健.付雨蛟.许杨.高宇.道如那.任海芬.赵家祥 本项目将实现基于服务器端Java Web网站的银行账户管理系统的原型部分,并且在该原型的基础上进行功能的扩展

个人银行账户小程序

#if 0 //1#ifndef _ACCOUNTH#define _ACCOUNTHclass SavingsAccount //储蓄账户{public:SavingsAccount(int date,int id,double rate);int getid()const{return id;}double getbalance()const{return balance;}double getrate(){return rate;}static double gettotal(){retu

创建一个银行类

# -*- conding:utf-8 -*- ''' 类: 创建一个银行类 属性: 一个属于银行的类属性 用来存储所有银行的开户信息,包含卡号.密码.用户名.余额 (外界不能随意访问和修改.开户时要进行卡号验证,查看卡号是否已经存在) 每个对象拥有 卡号,密码,用户名,余额 (外界不能随意访问和修改.) 方法:银行类拥有 查看本银行的开户总数 查看所有用户的个人信息(包含卡号,密码,用户名,余额) 每个对象拥有 实例化对象的时候传入相关参数 初始化对象及类属性 取钱(需要卡号和密码验证) 通过