一、线程安全问题
- 多个线程同时操作同一个共享资源的时候可能会出现业务安全问题,称为线程安全问题。
二、线程安全问题模型
取钱模型演示
- 需求:小明和小红事一对夫妻,拥有共同账户,余额10万元
- 如果小明和小红同时来取钱,而且2人都要取钱10万元,则会出现线程问题。
问题出现情况解释: - cpu执行线程任务:有可能先执行小明的线程,然后判断小明的线程任务1,查询的到结果是true。
- 此时出现某种原因,cpu执行小红线程任务,然后判断小红的线程任务1,此时得到的结果也是true。
- 此时假设小红线程继续执行,此时小红取到10万块钱。然后更新账户余额,此时的余额为0
- 小红线程结束,小明线程继续执行,由于任务1的结果是true,此时小明也是可以取出10万块钱。更新余额,此时余额称为-10万元
- 最后的记过就是两人都取了10万元,银行亏损10万元
三、线程安全问题出现的原因
- 存在多线程并发
- 同时访问共享资源
- 存在修改共享资源
总结:多个线程同时访问同一个共享资源且存在修改该资源
四、取钱业务代码案例
定义一个账户类,里边创建取钱的方法
/**
* @Author: {LZG}
* @ClassName: Account
* @Description: TODO
* @Date: 2022/5/10 1:26
**/
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){
// 3、取钱
System.out.println(name+"来取钱成功,吐出:"+money);
// 4、更新余额
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;
}
}
创建一个曲线的线程类
/**
* @Author: {LZG}
* @ClassName: DrawThread
* @Description: 取钱的线程类
* @Date: 2022/5/10 1:30
**/
public class DrawThread extends Thread{
private Account acc;
public DrawThread(String name,Account acc) {
super(name);
this.acc = acc;
}
@Override
public void run() {
// 取钱的
acc.drawMoney(100000);
}
}
客户测试
/**
* @Author: {LZG}
* @ClassName: ThreadDemo1
* @Description: TODO
* @Date: 2022/5/10 1:28
**/
public class ThreadDemo1 {
public static void main(String[] args) {
// 1、定义一个线程类,创建一个共享账户对象
Account account = new Account("ICBC-001",100000);
// 2、创建两个线程对象,代表小明和小红同时进来了
new DrawThread("小明",account).start();
new DrawThread("小红",account).start();
}
}
运行结果