通过发工资去消费的例子简单说明下显示生活中遇到的线程安全的情况
- 1、例子
- 2、原因
- 思考
1、例子
今天发工资3500块很开心,决定去按摩放松一下,花了两千,同时还要还上个月的一千块的花呗,这个时候应该还剩五百块吃饭的钱,此时代码如下:
public class ThreadDemo {
public static void main(String[] args) {
//创建银行账户,工资刚发3500块
BankAccount bankAccount = new BankAccount();
bankAccount.setBalance(3500);
//微信花两千按个摩奖励自己
MyRunnable massage = new MyRunnable(bankAccount, 2000, "微信");
//支付宝还上个月一千块的花呗
MyRunnable keyboard = new MyRunnable(bankAccount, 1000, "支付宝");
new Thread(massage).start();
new Thread(keyboard).start();
}
}
class MyRunnable implements Runnable {
//多个线程共享同一个账户对象,对同一个账户进行操作
private BankAccount bankAccount;
// 取款数量
private int quantity;
//取款方式
private String payType;
MyRunnable(BankAccount bankAccount,int quantity,String payType){
this.bankAccount = bankAccount;
this.quantity = quantity;
this.payType = payType;
}
@Override
public void run() {
bankAccount.withdraw(quantity,payType);
}
}
//账户类
class BankAccount {
//余额
private int balance;
// 取钱方法 传入取钱的金额,取款方式
public void withdraw(int withdrawalQuantity,String payType){
//取钱动作
int money = this.balance;
//加入Thread.sleep 100%会出现安全问题
System.out.println("账上的余额为:" + money);
System.out.println(payType+"从银行卡开始取钱"+withdrawalQuantity);
this.balance = money - withdrawalQuantity;
System.out.println(payType+"取完钱账户的钱的数量为:"+this.balance);
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
}
此时运行的结果为
2、原因
为什么我花了这么多还有2500?因为多个线程对同一个资源进行操作,在另一个线程还没完成更新操作的时候,当前线程读取了旧值,导致这个问题出现,要解决这个问题就要加入对共享资源的操作的同步机制,代码如下:
//账户类
class BankAccount {
//余额
private int balance;
// 取钱方法 传入取钱的金额,取款方式
public void withdraw(int withdrawalQuantity,String payType){
synchronized (this){
//取钱动作
int money = this.balance;
//加入Thread.sleep 100%会出现安全问题
System.out.println("账上的余额为:" + money);
System.out.println(payType+"从银行卡开始取钱"+withdrawalQuantity);
this.balance = money - withdrawalQuantity;
System.out.println(payType+"取完钱账户的钱的数量为:"+this.balance);
}
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
}
在withdraw()方法加入synchronized 使得其中的代码线程顺序执行,而避免了线程安全的问题
思考
使用一条语句直接操作会照成线程安全问题吗?
//账户类
class BankAccount {
//余额
private int balance;
// 取钱方法 传入取钱的金额,取款方式
public void withdraw(int withdrawalQuantity,String payType){
//加入Thread.sleep 100%会出现安全问题
System.out.println("账上的余额为:" + this.balance);
System.out.println(payType+"从银行卡开始取钱"+withdrawalQuantity);
this.balance = balance - withdrawalQuantity;
System.out.println(payType+"取完钱账户的钱的数量为:"+this.balance);
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
}
代码地址:gitee代码地址