zoukankan      html  css  js  c++  java
  • 线程同步问题

      1.多个线程对同一个账户取钱的模拟操作(未加线程安全控制,则会出现非法操作)

        (1)账户类

          

    /**
     * 
     * @author fengkuirui
     * @Date 2017-02-10
     * 实现银行取钱问题;
     * 此类为账户类;
     */
    public class Account {
        
        private String accountNo;//账户号
        private double balance;//余额
        public Account(){};
        public Account(String accountNo, double balance){
            this.accountNo = accountNo;
            this.balance = balance;
        }
        public String getAccountNo() {
            return accountNo;
        }
        public void setAccountNo(String accountNo) {
            this.accountNo = accountNo;
        }
        public double getBalance() {
            return balance;
        }
        public void setBalance(double balance) {
            this.balance = balance;
        }
        //重写hashCode方法
        public int hashCode(){
            return this.accountNo.hashCode();
        }
        //重写equals方法
        public boolean equals(Object obj){
            if(this == obj){//如果是同一个堆;
                return true;
            }
            //如果不是同一个对象;
            //如果都是Account的对象;
            if(obj != null && obj.getClass() == Account.class){
                Account account = (Account)obj;
                //判断账号是否一致;
                return account.getAccountNo().equals(this.accountNo);
            }
            return false;
        }
        
    }

        (2)多线程取钱类

          

    /**
     * 
     * @author fengkuirui
     * @date 2017-02-10
     * 多线程实现取钱操作;
     */
    public class DrawThread extends Thread{
        //模拟用户
        private Account account;
        //当前所希望的取钱数;
        private double drawAmount;
        public DrawThread(){};
        public DrawThread(String name,Account account, double drawAmount){
            super(name);
            this.account = account;
            this.drawAmount = drawAmount;
        }
        //当多个线程修改一个共享数据时,将涉及数据的安全问题;
        public void run(){
            //账户余额大于当前取的钱数可以取款
            if(this.account.getBalance() >= this.drawAmount){
                //吐钱;
                System.out.println(getName()+"取钱成功!吐出钞票:"+this.drawAmount);
                //修改余额
                account.setBalance(this.account.getBalance() - this.drawAmount);
                System.out.println("	余额为:"+this.account.getBalance());
            }else{
                System.out.println("余额不足"+getName()+"取钱失败!");
            }
        }
    }

          

        (3)测试类

          

    /**
     * 
     * @author fengkuirui
     * @date 2017-02-10
     * 测试类
     */
    public class DrawTest {
        public static void main(String[] args) {
            //创建一个账户
            Account account = new Account("123456",1000);
            //模拟两个线程对一个账户取钱;
            new DrawThread("甲",account,800).start();
            new DrawThread("乙",account,800).start();
        }
    }

        (4)非法结果;

          

      2.加入控制操作,防止出现非法操作

        (1)只需要修改多线程取钱类即可,其他类保持不变;(同步代码块)

          

    /**
     * 
     * @author fengkuirui
     * @date 2017-02-10
     * 多线程实现取钱操作;
     */
    public class DrawThread extends Thread{
        //模拟用户
        private Account account;
        //当前所希望的取钱数;
        private double drawAmount;
        public DrawThread(){};
        public DrawThread(String name,Account account, double drawAmount){
            super(name);
            this.account = account;
            this.drawAmount = drawAmount;
        }
        //当多个线程修改一个共享数据时,将涉及数据的安全问题;
        public void run(){
            //账户余额大于当前取的钱数可以取款
            
            //使用account作为同步监视器,任何线程进入下面得同步代码块之前
            //必须先获得对account账户的锁定,其他线程将无法获得该锁,也就是无法修改他
            //这种做法符合:加锁——修改——释放锁;
            synchronized(this.account){
            if(this.account.getBalance() >= this.drawAmount){
                //吐钱;
                System.out.println(getName()+"取钱成功!吐出钞票:"+this.drawAmount);
    //            try {
    //                Thread.sleep(1);
    //            } catch (Exception e) {
    //                // TODO: handle exception
    //                e.printStackTrace();
    //            }
                //修改余额
                account.setBalance(this.account.getBalance() - this.drawAmount);
                System.out.println("	余额为:"+this.account.getBalance());
            }else{
                System.out.println("余额不足"+getName()+"取钱失败!");
            }
            }
        }
    }

        (2)同步方法保证线程安全

          在Account类中,添加一个取钱方法,改为同步

          代码如下:

            

    /**
     * 
     * @author fengkuirui
     * @Date 2017-02-10
     * 实现银行取钱问题;
     * 此类为账户类;
     */
    public class Account {
        
        private String accountNo;//账户号
        private double balance;//余额
        public Account(){};
        public Account(String accountNo, double balance){
            this.accountNo = accountNo;
            this.balance = balance;
        }
        public String getAccountNo() {
            return accountNo;
        }
        public void setAccountNo(String accountNo) {
            this.accountNo = accountNo;
        }
        public double getBalance() {
            return balance;
        }
        public void setBalance(double balance) {
            this.balance = balance;
        }
        //重写hashCode方法
        public int hashCode(){
            return this.accountNo.hashCode();
        }
        //重写equals方法
        public boolean equals(Object obj){
            if(this == obj){//如果是同一个堆;
                return true;
            }
            //如果不是同一个对象;
            //如果都是Account的对象;
            if(obj != null && obj.getClass() == Account.class){
                Account account = (Account)obj;
                //判断账号是否一致;
                return account.getAccountNo().equals(this.accountNo);
            }
            return false;
        }
        public synchronized void draw(double drawAmount){
            if(balance >=drawAmount){
                //吐钱;
                System.out.println(Thread.currentThread().getName()+"取钱成功!吐出钞票:"+drawAmount);
                try {
                    Thread.sleep(1);
                } catch (Exception e) {
                    // TODO: handle exception
                    e.printStackTrace();
                }
                //修改余额
                balance -= drawAmount;
                System.out.println("	余额为:"+balance);
            }else{
                System.out.println("余额不足"+Thread.currentThread().getName()+"取钱失败!");
            }
        }
        
    }

        

    package com.fkr.code12_2;
    /**
     * 
     * @author fengkuirui
     * @date 2017-02-10
     * 多线程实现取钱操作;
     */
    public class DrawThread extends Thread{
        //模拟用户
        private Account account;
        //当前所希望的取钱数;
        private double drawAmount;
        public DrawThread(){};
        public DrawThread(String name,Account account, double drawAmount){
            super(name);
            this.account = account;
            this.drawAmount = drawAmount;
        }
        public void run(){
            account.draw(drawAmount);
        }
    }
  • 相关阅读:
    Linux远程复制scp和rsync区别
    一个线上问题的思考:Eureka注册中心集群如何实现客户端请求负载及故障转移?
    docker离线安装
    centos7 docker 宿主机不能访问容器问题解决
    nginx 或 tengine安装错误提示:./configure: error: the HTTP rewrite module requires the PCRE library
    redhat 安装中文 支持中文
    rpm忽略依赖,强制安装,加--force --nodeps ( warning: perl-Test-Nginx-0.28-1.el6_10.noarch.rpm: Header V4 RSA/SHA1 Signature, key ID d5edeb74: NOKEY error: Failed dependencies:)
    redhat6 安装openresty
    redhat6 Unable to establish SSL connection.
    Lua入门脚本(与Redis结合)
  • 原文地址:https://www.cnblogs.com/fkrcode/p/6385410.html
Copyright © 2011-2022 走看看