Java案例分析
【案例8-3】 模拟银行存取钱
2024-10-25 46 0
简介 1.任务描述 在银行办理业务时,通常银行会开多个窗口,客户排队等候,窗口办理完业务,会呼叫下一个用户办理业务。本案例要求编写一个程序模拟银行存取钱业务办理。假如有两个用户在存取钱,两个用户分别操作各自的账户,并在控制台打印存取钱的数量以及账户的余额。
【案例8-3】 模拟银行存取钱
【案例介绍】
1.任务描述
在银行办理业务时,通常银行会开多个窗口,客户排队等候,窗口办理完业务,会呼叫下一个用户办理业务。本案例要求编写一个程序模拟银行存取钱业务办理。假如有两个用户在存取钱,两个用户分别操作各自的账户,并在控制台打印存取钱的数量以及账户的余额。
2.运行结果
运行结果如图8-1所示。
图8-1 运行结果
【案例目标】
l 学会分析“模拟银行存取钱功能”任务实现的逻辑思路。
l 能够独立完成“模拟银行存取钱功能”程序的源代码编写、编译以及运行。
l 通过存取款线程理解多线程安全问题的发生原因,并掌握如何解决多线程安全问题。
【案例思路】
(1) 通过任务描述和运行结果可以看出,该任务需要使用多线程的相关知识来实现。由于两个用户操作各自的账户,因此我们需要创建两个线程完成每个用户的操作。这里我们使用实现Runnable接口的方法来创建线程。
(2) 既然是储户去银行存款,那么可以得出该任务会涉及到三个类,分别是银行类、储户类和测试类。
(3) 定义一个实体类作为账务的集合,包括用户名、登录名、登录密码、钱包、取钱时间和存钱时间等字段。
(4) 在银行类中需要定义一个账户的实体类、一个存钱的方法、一个取钱的方法、查询余额的方法和获取当前用户的方法。获取当前用户方法需要使用synchronized线程锁判断是哪一位用户,在存钱和取钱的方法中先调用获取用户方法判断操作者,再进行存取钱操作,需要注意的是在进行取钱操作时,需要判断余额是否大于需要取的钱数。
(5) 在测试类中使用for循环调用线程模拟用户存取钱操作。
【案例代码】
(1) 创建用户类
定义一个用户的类,根据用户实现多人同时存取钱功能,如文件8-1所示。
文件8-1 User.java
1 package chapter0803;
2 import java.util.Date;
3 public class User {
4 private String u_name;//用户名
5 private String u_login_name;//登录名 卡的id
6 private String u_login_pwd;//登录密码
7 private String u_wallet;//钱包
8 private Date draw_money_time;//取钱时间
9 private Date save_money_time;//存钱时间
10 public User(){}
11 public User(String u_name, String u_login_name, String u_login_pwd,
12 String u_wallet) {
13 this.u_name = u_name;
14 this.u_login_name = u_login_name;
15 this.u_login_pwd = u_login_pwd;
16 this.u_wallet = u_wallet;
17 }
18 public User(String u_name, String u_login_name, String u_login_pwd,
19 String u_wallet, Date draw_money_time, Date save_money_time) {
20 this.u_name = u_name;
21 this.u_login_name = u_login_name;
22 this.u_login_pwd = u_login_pwd;
23 this.u_wallet = u_wallet;
24 this.draw_money_time = draw_money_time;
25 this.save_money_time = save_money_time;
26 }
27 public String getU_name() {
28 return u_name;
29 }
30 public void setU_name(String u_name) {
31 this.u_name = u_name;
32 }
33 public String getU_login_name() {
34 return u_login_name;
35 }
36 public void setU_login_name(String u_login_name) {
37 this.u_login_name = u_login_name;
38 }
39 public String getU_login_pwd() {
40 return u_login_pwd;
41 }
42 public void setU_login_pwd(String u_login_pwd) {
43 this.u_login_pwd = u_login_pwd;
44 }
45 public String getU_wallet() {
46 return u_wallet;
47 }
48 public void setU_wallet(String u_wallet) {
49 this.u_wallet = u_wallet;
50 }
51 public Date getDraw_money_time() {
52 return draw_money_time;
53 }
54 public void setDraw_money_time(Date draw_money_time) {
55 this.draw_money_time = draw_money_time;
56 }
57 public Date getSave_money_time() {
58 return save_money_time;
59 }
60 public void setSave_money_time(Date save_money_time) {
61 this.save_money_time = save_money_time;
62 }
63 }
(2) 创建银行业务类
定义一个业务类,实现用户的存取钱功能,如文件8-2所示。
文件8-2 Bank.java
1 package chapter0803;
2 import java.math.BigDecimal;
3 import java.text.SimpleDateFormat;
4 import java.util.ArrayList;
5 import java.util.Date;
6 import java.util.List;
7 public class Bank {
8 private List<User> userList=new ArrayList<User>();
9 public Bank(List<User> userList) {
10 this.userList = userList;
11 }
12 public List<User> getUserList() {
13 return userList;
14 }
15 public void setUserList(List<User> userList) {
16 this.userList = userList;
17 }
18 //存钱
19 public Boolean saveMoney(String card,String pwd,String moneyNum){
20 User u=getUserByCard(card);
21 synchronized (Bank.class) {
22 if (u.getU_login_name().equals(card) &&
23 u.getU_login_pwd().equals(pwd)) {
24 BigDecimal oldData=new BigDecimal(u.getU_wallet());
25 BigDecimal money=new BigDecimal(moneyNum);
26 u.setU_wallet(oldData.add(money).toString());
27 u.setSave_money_time(new Date());
28 System.out.println(Thread.currentThread().getName()+"存钱
29 ---->"+u.getU_name()+"在"+new SimpleDateFormat("yyyy-MM-dd
30 HH:mm:ss").format(u.getSave_money_time())+"存["+moneyNum+"]钱,余额:
31 "+u.getU_wallet());
32 return true;
33 }
34 }
35 System.out.println(getUserByCard(card).getU_name()+"存钱失败");
36 return false;
37 }
38 //取钱
39 public Boolean getMoney(String card,String pwd,String moneyNum){
40 User u=getUserByCard(card);
41 synchronized (Bank.class) {
42 if (u!=null && u.getU_login_name().equals(card) &&
43 u.getU_login_pwd().equals(pwd)) {
44 BigDecimal oldData=new BigDecimal(u.getU_wallet());
45 BigDecimal money=new BigDecimal(moneyNum);
46 if(oldData.compareTo(money)>=0){
47 u.setU_wallet(oldData.subtract(money).toString());
48 u.setDraw_money_time(new Date());
49 System.out.println(Thread.currentThread().getName()+"取钱
50 ---->"+u.getU_name()+"在"+new SimpleDateFormat("yyyy-MM-dd
51 HH:mm:ss").format(u.getDraw_money_time())+"取["+moneyNum+"]钱
52 ,余额:"+u.getU_wallet());
53 return true;
54 }else {
55 System.out.println(getUserByCard(card).getU_name()+"
56 要取["+moneyNum+"]钱,但余额不足");
57 return false;
58 }
59 }
60 }
61 System.out.println(card+"取钱失败");
62 return false;
63 }
64 //查询余额
65 public String balanceEnquiry(String card,String pwd){
66 for(User u :this.userList){
67 if(u.getU_login_name().equals(card)&&
68 u.getU_login_pwd().equals(pwd)){
69 System.out.println(Thread.currentThread().getName()+":"
70 +u.getU_name()+"余额:"+u.getU_wallet());
71 return u.getU_wallet();
72 }
73 }
74 System.out.println(Thread.currentThread().getName()+":"+card+"
75 操作失败");
76 return null;
77 }
78 //获取当前用户
79 public synchronized User getUserByCard(String card){
80 for(User u :this.userList){
81 if(u.getU_login_name().equals(card)){
82 return u;
83 }
84 }
85 return null;
86 }
87 public void delayTime(Integer nim){
88 try {
89 Thread.sleep(nim);
90 } catch (InterruptedException e) {
91 e.printStackTrace();
92 }
93 }
94 }
(3) 创建测试类
定义测试类,在类中创建客户对象,并创建和开启线程执行存取钱操作,如文件8-3所示。
1 package chapter0803;
2 import java.util.ArrayList;
3 import java.util.List;
4 public class BankText {
5 public static void main(String[] args) throws Exception {
6 User u = new User("张三", "132466", "123", "100");
7 User uu = new User("李四", "4600882", "123", "0");
8 List<User> list = new ArrayList<User>();
9 list.add(u);
10 list.add(uu);
11 final Bank atm = new Bank(list);//初始化数据 模拟
12 Thread t = new Thread() {
13 public void run() {
14
15 for (int i = 0; i < 10; i++) {
16 atm.saveMoney("132466", "123", "12");
17 atm.delayTime(250);
18 atm.getMoney("4600882", "123", "14");
19 atm.delayTime(250);
20 }
21
22 }
23 };
24 Thread tt = new Thread() {
25 public void run() {
26
27 for (int i = 0; i < 10; i++) {
28 atm.getMoney("132466", "123", "2");
29 atm.delayTime(250);
30 atm.saveMoney("4600882", "123", "12");
31 atm.delayTime(250);
32 }
33 }
34 };
35 t.start();
36 tt.start();
37 }
38 }