zoukankan      html  css  js  c++  java
  • 线程通信安全问题

    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;
        }
    }
    
  • 相关阅读:
    算法总结之 两个链表生成相加链表
    算法总结之 复制含有随机指针节点的链表
    算法总结之 将单向链表按某值划分成左边小、中间相等、右边大的形式
    在PHP5.3以上版本运行ecshop和ecmall出现的问题及解决方案
    windows下配置nginx+php环境
    ecmall程序结构图与数据库表分析
    ecmall数据字典
    Ecmall二次开发-增删改查操作
    PHP7:10件事情你需要知道的
    PHP命名空间规则解析及高级功能3
  • 原文地址:https://www.cnblogs.com/Guard9/p/11153124.html
Copyright © 2011-2022 走看看