多线程----银行取款问题(非线程安全问题)
背景
张三在银行存了10000元钱,突发奇想,让两个人在柜台和ATM同时取出6000元(完全相同时间),能得到12000元吗?
简易银行交互系统
package com.woongcha;
public class UnsafeBank implements Runnable {
private int cash;
private Bank bank;
public UnsafeBank(int cash, Bank bank) {
this.cash = cash;
this.bank = bank;
}
@Override
public void run() {
if (cash>bank.money){
System.out.println(Thread.currentThread().getName()+"想要取走"+bank.name+"的"+cash+"元");
System.out.println("超出取款数量");
}else {
System.out.println(bank.name+"的钱被"+Thread.currentThread().getName()+"取走"+cash+"元");
int sum=bank.money-cash;
bank.money=sum;
System.out.println("余额"+sum);
}
}
public static void main(String[] args) {
Bank bank = new Bank(10000,"张三");
UnsafeBank unsafeBank = new UnsafeBank(6000,bank);
UnsafeBank unsafeBank1 = new UnsafeBank(5000,bank);
Thread thread = new Thread(unsafeBank,"张三");
Thread thread1 = new Thread(unsafeBank1,"李四");
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread1.start();
}
}
class Bank {
int money;
String name;
public Bank(int money, String name) {
this.money = money;
this.name = name;
}
}
分析
因为两个线程同时进行,进入银行时,账户上都显示有10000元,所以ATM和支付宝上各得到6000和5000元,但实际情况肯定是不允许的。
当加入线程休眠后
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread运行一秒后,thread1才开始运行,由于计算速度非常快,足够更新账户余额。
新的问题 当有大量线程操作时,线程休眠间隔调为多少才合适,1秒会不会浪费大量时间,1毫秒会不会时间不够?
synchronized
线程同步的出现解决了上述的问题
synchronized可以作用在类或者代码块中,当用在类中锁的是类本身,放在代码块中可以锁任意属性。
synchronized (bank) {
if (cash > bank.money) {
System.out.println(Thread.currentThread().getName() + "想要取走" + bank.name + "的" + cash + "元");
System.out.println("超出取款数量");
} else {
System.out.println(bank.name + "的钱被" + Thread.currentThread().getName() + "取走" + cash + "元");
int sum = bank.money - cash;
bank.money = sum;
System.out.println("余额" + sum);
}
}
问题解决。