• 线程通信安全问题


    1- 线程安全问题

    线程安全:多个线程操作同一个共享资源的时候可能出现线程安全问题。

    /**
    先模拟一个线程安全问题的案例:转账功能。
    
    分析:整存整取。
    	(1)定义一个账户(余额,卡号)。
    	(2)定义一个取钱的线程类
    	(3)创建一个账户对象,创建2个线程对象,去这个账户对象取钱10000
    
    小结:
    	多个线程操作同一个共享资源的时候可能出现线程安全问题。
     */
    public class ThreadSave {
        public static void main(String[] args) {
            // 1.创建一个共享资源:是一个账户对象。这个对象必须只有一个。
            Account acc = new Account("ICBC-110", 10000 );
    
            // 2.创建2个线程对象代表小明和小红
            DrawThread xiaoMing = new DrawThread("小明",acc);
            xiaoMing.start();
    
            DrawThread xiaoRed = new DrawThread("小红",acc);
            xiaoRed.start();
        }
    }
    /**
        取钱的线程类。
     */
    public class DrawThread extends Thread {
        // 定义一个成员变量接收账户对象
        private Account acc;
        public DrawThread(String name , Account acc){
            super(name);
            this.acc = acc;
        }
        @Override
        public void run() {
            // 去账户acc中取钱
            acc.drawMoney(10000);
        }
    }
    
    /**
     * 账户对象:
     */
    public class Account {
        private String cardId ;
        private double money ; // 余额
        public Account() {
    
        }
        public Account(String cardId, double money) {
            this.cardId = cardId;
            this.money = money;
        }
        // 小明和小红都到这里来了
        public void drawMoney(double money) {
            // 1.先拿到是谁来取钱:拿到当前线程的名字即可,名字是谁就是谁来取钱
            String name = Thread.currentThread().getName();
            // 2.判断余额是否足够
            if(this.money >= money){
                // 钱够了
                System.out.println(name+"来取钱,余额足够,吐出:"+money);
                // 3.更新余额
                this.money -= money;
                System.out.println(name+"取钱后剩余:"+this.money);
            }else{
                // 钱不够
                System.out.println(name+"来取钱,余额不足");
            }
        }
        public String getCardId() {
            return cardId;
        }
    
        public void setCardId(String cardId) {
            this.cardId = cardId;
        }
    
        public double getMoney() {
            return money;
        }
    
        public void setMoney(double money) {
            this.money = money;
        }
    }
    

    2-线程同步方式

    同步代码块

    /**
     * 账户对象:
     */
    public class Account {
        private String cardId ;
        private double money ; // 余额
        public Account() {
        }
    
        public Account(String cardId, double money) {
            this.cardId = cardId;
            this.money = money;
        }
        // 小明和小红都到这里来了
        public void drawMoney(double money) {
            // 1.先拿到是谁来取钱:拿到当前线程的名字即可,名字是谁就是谁来取钱
            String name = Thread.currentThread().getName();
            // 2.判断余额是否足够 : 和小红
            synchronized (this){  // this == acc
                //小明
                if(this.money >= money){
                    // 钱够了
                    System.out.println(name+"来取钱,余额足够,吐出:"+money);
                    // 3.更新余额
                    this.money -= money;
                    System.out.println(name+"取钱后剩余:"+this.money);
                }else{
                    // 钱不够
                    System.out.println(name+"来取钱,余额不足");
                }
            }
        }
        public String getCardId() {
            return cardId;
        }
    
        public void setCardId(String cardId) {
            this.cardId = cardId;
        }
    
        public double getMoney() {
            return money;
        }
    
        public void setMoney(double money) {
            this.money = money;
        }
    }
    

    同步方法

    /**
     * 账户对象:
     */
    public class Account {
        private String cardId ;
        private double money ; // 余额
        public Account() {
    
        }
        public Account(String cardId, double money) {
            this.cardId = cardId;
            this.money = money;
        }
        // 小明和小红都到这里来了
        public synchronized void drawMoney(double money) {
            // 1.先拿到是谁来取钱:拿到当前线程的名字即可,名字是谁就是谁来取钱
            String name = Thread.currentThread().getName();
            // 2.判断余额是否足够 : 和小红
            //小明
            if(this.money >= money){
                // 钱够了
                System.out.println(name+"来取钱,余额足够,吐出:"+money);
                // 3.更新余额
                this.money -= money;
                System.out.println(name+"取钱后剩余:"+this.money);
            }else{
                // 钱不够
                System.out.println(name+"来取钱,余额不足");
            }
        }
        public String getCardId() {
            return cardId;
        }
    
        public void setCardId(String cardId) {
            this.cardId = cardId;
        }
    
        public double getMoney() {
            return money;
        }
    
        public void setMoney(double money) {
            this.money = money;
        }
    }
    

    同步锁

    /**
     * 账户对象:
     */
    public class Account {
        private String cardId ;
        private double money ; // 余额
        // 创建一把锁对象:必须保证这个对象唯一
        private final Lock lock = new ReentrantLock();
    
        public Account() {
    
        }
    
        public Account(String cardId, double money) {
            this.cardId = cardId;
            this.money = money;
        }
        // 小明和小红都到这里来了
        public  void drawMoney(double money) {
            // 1.先拿到是谁来取钱:拿到当前线程的名字即可,名字是谁就是谁来取钱
            String name = Thread.currentThread().getName();
            // 2.判断余额是否足够 : 和小红
            //小明
            lock.lock();
            try{
                if(this.money >= money){
                    // 钱够了
                    System.out.println(name+"来取钱,余额足够,吐出:"+money);
                    // 3.更新余额
                    this.money -= money;
                    System.out.println(name+"取钱后剩余:"+this.money);
                }else{
                    // 钱不够
                    System.out.println(name+"来取钱,余额不足");
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock(); // 解锁操作!
            }
        }
    
        public String getCardId() {
            return cardId;
        }
    
        public void setCardId(String cardId) {
            this.cardId = cardId;
        }
    
        public double getMoney() {
            return money;
        }
    
        public void setMoney(double money) {
            this.money = money;
        }
    }
    
  • 相关阅读:
    HDU 1263 二维map
    POJ 1442 优先队列
    Windows小白学习笔记
    毕设:高校考试信息数字化平台(六)——通过form外按钮提交表单
    毕设:高校考试信息数字化平台(五)——Spring框架中的登录问题
    毕设:高校考试信息数字化平台(四)——WEB-INF内部的jsp文件引用css
    毕设:高校考试信息数字化平台(三)——阿里云ECS的项目部署相关问题
    毕设:高校考试信息数字化平台(二)——Spring中静态文件无法获取的问题(Bootstrap样式无法显示)
    毕设:高校考试信息数字化平台(一)——SpringMVC的配置
    我的2018秋招之路(非面筋,纯属个人日记)
  • 原文地址:https://www.cnblogs.com/Guard9/p/11153124.html
Copyright © 2020-2023  润新知