Java 多线程 模拟银行ATM实时存取钱

近期想回顾一些知识:
一、Java 多线程
一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。这里定义和线程相关的另一个术语 - 进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束。多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。

二、区别

  • 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1–n个线程。(进程是资源分配的最小单位)
  • 线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)
  • 线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止。
  • 多进程是指操作系统能同时运行多个任务(程序)。
  • 多线程是指在同一程序中有多个顺序流在执行。

三、模拟银行ATM存取钱
1、 用户类user,存储用户信息

import java.util.Date;
public class User {
    private String u_name;//用户名
    private String u_login_name;//登录名 卡的id
    private String u_login_pwd;//登录密码
    private String u_wallet;//钱包
    private Date  draw_money_time;//取钱时间
    private Date  save_money_time;//存钱时间
    public User(){}
    public User(String u_name, String u_login_name, String u_login_pwd, String u_wallet) {
        this.u_name = u_name;
        this.u_login_name = u_login_name;
        this.u_login_pwd = u_login_pwd;
        this.u_wallet = u_wallet;
    }
    public User(String u_name, String u_login_name, String u_login_pwd, String u_wallet, Date draw_money_time, Date save_money_time) {
        this.u_name = u_name;
        this.u_login_name = u_login_name;
        this.u_login_pwd = u_login_pwd;
        this.u_wallet = u_wallet;
        this.draw_money_time = draw_money_time;
        this.save_money_time = save_money_time;
    }

    public String getU_name() {
        return u_name;
    }

    public void setU_name(String u_name) {
        this.u_name = u_name;
    }

    public String getU_login_name() {
        return u_login_name;
    }

    public void setU_login_name(String u_login_name) {
        this.u_login_name = u_login_name;
    }

    public String getU_login_pwd() {
        return u_login_pwd;
    }

    public void setU_login_pwd(String u_login_pwd) {
        this.u_login_pwd = u_login_pwd;
    }

    public String getU_wallet() {
        return u_wallet;
    }

    public void setU_wallet(String u_wallet) {
        this.u_wallet = u_wallet;
    }

    public Date getDraw_money_time() {
        return draw_money_time;
    }

    public void setDraw_money_time(Date draw_money_time) {
        this.draw_money_time = draw_money_time;
    }

    public Date getSave_money_time() {
        return save_money_time;
    }

    public void setSave_money_time(Date save_money_time) {
        this.save_money_time = save_money_time;
    }
}

2、 取款类ATM:有取款机的相应功能

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
 * 取款机
 * 2018/6/8
 * wtj
 */
public class ATM {
    private List userList=new ArrayList<>();
    public ATM(){}

    public  ATM(List userList) {
         this.userList = userList;
    }

    public  List getUserList() {
        return userList;
    }

    public void setUserList(List userList) {
        this.userList = userList;
    }
    //存钱
    public Boolean saveMoney(String card,String pwd,String moneyNum){
        User u=getUserByCard(card);
        synchronized (ATM.class) {
                if (u.getU_login_name().equals(card) && u.getU_login_pwd().equals(pwd)) {
                    BigDecimal oldData=new BigDecimal(u.getU_wallet());
                    BigDecimal money=new BigDecimal(moneyNum);
                    u.setU_wallet(oldData.add(money).toString());
                    u.setSave_money_time(new Date());
                    System.out.println(Thread.currentThread().getName()+"存钱---->"+u.getU_name()+"在"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(u.getSave_money_time())+"存["+moneyNum+"]钱,余额:"+u.getU_wallet());
                    return true;
                }
            }
        System.out.println(getUserByCard(card).getU_name()+"存钱失败");
      return false;
    }
    //取钱
    public Boolean getMoney(String card,String pwd,String moneyNum){
        User u=getUserByCard(card);
        synchronized (ATM.class) {
                if (u!=null && u.getU_login_name().equals(card) && u.getU_login_pwd().equals(pwd)) {
                    BigDecimal oldData=new BigDecimal(u.getU_wallet());
                    BigDecimal money=new BigDecimal(moneyNum);
                    if(oldData.compareTo(money)>=0){
                        u.setU_wallet(oldData.subtract(money).toString());
                        u.setDraw_money_time(new Date());
                        System.out.println(Thread.currentThread().getName()+"取钱---->"+u.getU_name()+"在"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(u.getDraw_money_time())+"取["+moneyNum+"]钱,余额:"+u.getU_wallet());
                        return true;
                    }else {
                        System.out.println(getUserByCard(card).getU_name()+"余额不足");
                        return false;
                    }
                }
            }
        System.out.println(card+"取钱失败");
        return false;
    }
    //查询余额
    public String balanceEnquiry(String card,String pwd){
        for(User u :this.userList){
            if(u.getU_login_name().equals(card)&& u.getU_login_pwd().equals(pwd)){
                System.out.println(Thread.currentThread().getName()+":"+u.getU_name()+"余额:"+u.getU_wallet());
                return u.getU_wallet();
            }
        }
        System.out.println(Thread.currentThread().getName()+":"+card+"操作失败");
        return null;
    }
   //获取当前用户
    public synchronized User getUserByCard(String card){
        for(User u :this.userList){
            if(u.getU_login_name().equals(card)){
                return u;
            }
        }
        return null;
    }
    public void delayTime(Integer nim){
        try {
            Thread.sleep(nim);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

3、测试类:模拟多次存取钱

import java.util.ArrayList;
import java.util.List;

public class TreadTextMain {
    public static void main(String[] args) throws Exception {
        User u = new User("赵云", "132466", "123", "100");
        User uu = new User("鲁班", "4600882", "123", "0");
        List list = new ArrayList<>();
        list.add(u);
        list.add(uu);
        ATM atm = new ATM(list);//初始化数据 模拟
        Thread t = new Thread() {
            public void run() {
//                ATM atm = new ATM(list);
                for (int i = 0; i < 20; i++) {
                    atm.saveMoney("132466", "123", "12");
                    atm.delayTime(250);
                    atm.getMoney("4600882", "123", "14");
                    atm.delayTime(250);
                }
//                atm.balanceEnquiry("4600882", "123");
//                atm.balanceEnquiry("132466", "123");
            }
        };

        Thread tt = new Thread() {
            public void run() {
//                ATM atm = new ATM(list);
                for (int i = 0; i < 20; i++) {
                    atm.getMoney("132466", "123", "2");
                    atm.delayTime(250);
                    atm.saveMoney("4600882", "123", "12");
                    atm.delayTime(250);
                }
//                atm.balanceEnquiry("4600882", "123");
//                atm.balanceEnquiry("132466", "123");

            }
        };
        t.start();
        tt.start();
//        atm.balanceEnquiry("4600882", "123");
//        atm.balanceEnquiry("132466", "123");
    }
}

四、总结
(1)synchronized的使用:synchronized可以使用在方法上,也可以使用在代码块上;如果我们需要用到不同的线程(多线程),注意synchronized(xxx.class){}、synchronized(this){} 后的效果;
看这篇文章https://www.cnblogs.com/huansky/p/8869888.html
(2)线程安全,简单的理解:多线程执行代码的结果,要跟单流程执行代码的结果一样;

你可能感兴趣的:(Java)