线程安全问题

文章目录

问题引入

不考虑线程同步程序运行后的结果:

小明取钱100000.0

小红取钱100000.0

小明取完后,余额:0.0

小红取完后,余额:-100000.0

银行亏钱了?嘿嘿,我有一个大胆的想法

代码
java 复制代码
class Test {
    public static void main(String[] args) {
        account acc = new account("ICBC-110",100000);
        new drawThread(acc,"小明").start();
        new drawThread(acc,"小红").start();
    }
}


class account {
    private String ID;
    private double money;

    public account() {
    }

    public account(String ID, double money) {
        this.ID = ID;
        this.money = money;
    }

    public String getID() {
        return ID;
    }

    public void setID(String ID) {
        this.ID = ID;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public void drawMoney(double money) {
        //区分谁来取钱
        String name = Thread.currentThread().getName();

        //取钱步骤
        if (this.money >= money) {
            System.out.println(name+"取钱"+money);
            this.money -= money;
            System.out.println(name+"取完后,余额:"+this.money);
        }else {
            System.out.println(name +"来取钱,余额不足~");
        }
    }
}

 class drawThread extends Thread{
    private account acc;
    public drawThread(account acc,String name)
    {
        super(name);
        this.acc = acc;
    }
    @Override
    public void run() {
        // 取钱
        acc.drawMoney(100000);
    }
}

线程安全问题出现的原因是什么?

  • 存在多个线程在同时执行:两个人同时取钱
  • 同时访问一个共享资源:同一个账户
  • 存在修改该共享资源:修改余额

那我们应该怎么解决这一问题呢。

方法一:同步代码块

synchronized 就是一个锁,每当一个线程运行到这里时会给这个线程加锁,然后才能执行同步代码块里面的代码,执行完后再进行解锁,让下一个进行重复当前步骤。

java 复制代码
    public void drawMoney(double money) {
        //区分谁来取钱
        String name = Thread.currentThread().getName();

        synchronized ("取钱") {
            //取钱步骤
            if (this.money >= money) {
                System.out.println(name+"取钱"+money);
                this.money -= money;
                System.out.println(name+"取完后,余额:"+this.money);
            }else {
                System.out.println(name +"来取钱,余额不足~");
            }
        }
    }
改进

"取钱"是一个字符串,在常量池里面,就一份,假如又多了俩人小黑和小白,这俩人操作的是同一个账户,那这样的话定义成 "取钱" 这一对象就不能达到想要效果(执行效果是小红或者小明取钱的时候小黑或者小白也不能取钱)

java 复制代码
    public void drawMoney(double money) {
        //区分谁来取钱
        String name = Thread.currentThread().getName();

        synchronized (this) {
            // 这里改成this,原来的字符串防的是所有的,比如小红取,小黑、白也不能取![请添加图片描述](https://img-blog.csdnimg.cn/5c8eba6dfa7f40e7ac2ce2ab79057669.png)

            //取钱步骤
            if (this.money >= money) {
                System.out.println(name+"取钱"+money);
                this.money -= money;
                System.out.println(name+"取完后,余额:"+this.money);
            }else {
                System.out.println(name +"来取钱,余额不足~");
            }
        }
    }

方法二:同步方法

java 复制代码
   public synchronized void drawMoney(double money) {
        //区分谁来取钱
        String name = Thread.currentThread().getName();
        //取钱步骤
        if (this.money >= money) {
            System.out.println(name+"取钱"+money);
            this.money -= money;
            System.out.println(name+"取完后,余额:"+this.money);
        }else {
            System.out.println(name +"来取钱,余额不足~");

        }
    }

方法三:lock

java 复制代码
private Lock lk = new ReentrantLock();

每个账户对象都应该有一个锁对象。方便锁住访问同一对象的线程

java 复制代码
     public void drawMoney(double money) {
        //区分谁来取钱
        String name = Thread.currentThread().getName();
        lk.lock();
        try {
            //取钱步骤
            if (this.money >= money) {
                System.out.println(name+"取钱"+money);
                this.money -= money;
                System.out.println(name+"取完后,余额:"+this.money);
            }else {
                System.out.println(name +"来取钱,余额不足~");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lk.unlock();
        }
    }
相关推荐
我星期八休息6 分钟前
C++智能指针全面解析:原理、使用场景与最佳实践
java·大数据·开发语言·jvm·c++·人工智能·python
摇滚侠6 分钟前
Spring Boot 3零基础教程,WEB 开发 整合 Thymeleaf 笔记36
java·spring boot·笔记
大猫会长10 分钟前
docker安装php+apache
java·开发语言
野生技术架构师13 分钟前
JAVA 架构师面试题含答案:JVM+spring+ 分布式 + 并发编程
java·jvm·spring
瑞士卷@25 分钟前
MyBatis入门到精通(Mybatis学习笔记)
java·数据库·后端·mybatis
梵得儿SHI35 分钟前
Java 反射机制深度剖析:性能与安全性的那些坑
java·开发语言·安全·反射·动态代理·性能·反射机制
虫小宝41 分钟前
Java分布式架构下的电商返利APP技术选型与架构设计实践
java·分布式·架构
007php00744 分钟前
百度面试题解析:Zookeeper、ArrayList、生产者消费者模型及多线程(二)
java·分布式·zookeeper·云原生·职场和发展·eureka·java-zookeeper
4Forsee1 小时前
【Android】浅析 Android 的 IPC 跨进程通信机制
android·java
来旺1 小时前
互联网大厂Java面试全解析及三轮问答专项
java·数据库·spring boot·安全·缓存·微服务·面试