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;
        }
    }
    
  • 相关阅读:
    【多线程】-实现多线程的三种方法
    在java项目启动时就执行某操作
    PHP上传多个Excel表格里的数据到数据库然后在页面显示
    PHP如何生成word并下载
    PHP把网页表单导出到word
    把PHP网页表单导出到word文档中
    HTTP Keep-Alive的作用
    利用paramiko获取上传下载远程服务器的资源信息
    3.django连接mysql数据库及安装mysqldb驱动报错解决办法
    3.Pycharm和navicate的使用
  • 原文地址:https://www.cnblogs.com/Guard9/p/11153124.html
Copyright © 2011-2022 走看看