【1】对于同步需要完成的两个操作
>吧竞争访问资源标识为private
>同步那些访问资源的代码,使用synchronized关键字来修饰方法或代码块。当synchronized方法执行完或者发生异常自动释放锁
【案例】
>模拟银行取钱,某银行卡账号上有500,一个人拿着存折去取钱,另外一个人拿着ATM去取钱,各自取钱400,要求取钱过程中不能出现资源竞争
>没有使用synchronized去模拟取钱的情况
public class BankDem0 {
public static void main(String[] args) {
Bank bank = new Bank();
BankThread b1 = new BankThread(bank);//模拟存折取款
b1.start();
BankThread b2 = new BankThread(bank);//模拟ATM机取款
b2.start();
}
}
class BankThread extends Thread{
private Bank bank = null;
public BankThread(Bank bank) {
this.bank = bank;
}
@Override
public void run() {
System.out.println("取款"+bank.getMoney(400));//设置取款金额为500
}
}
class Bank{
private int money = 500;
public int getMoney(int number) {
if(number < 0) {//判断取款金额是否正确
return -1;
}else if(money < 0) {//判断账户里面的余额是否正确
return -2;
}else if(number > money) {//判断取款金额是否超过存折里面的金额
return -3;
}else {
try {
Thread.sleep(1000);//休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
money-=number;//取钱之后存款的余额
System.out.println("余额"+money);//输出余额
return number;
}
}
>输出结果
余额-300 余额100
取款400 取款400
余额-300 余额-300
取款400 取款400
>结果分析
(1) 对于出现结果1,我们可以这样理解,当b1执行的时候调用run()方法,然后在调用getMoney()方法,此时符合这里面的前三个判断,则此时需要休眠1秒,而此时b2开始执行了,当b2页执行到这里的时候,b1开始进行money-=number,此时余额为100,而此时b2休眠完了,也执行到这里,故余额为100-400=-300,此时b1和b2共同执行输出语句,就会出现余额为-300
(2) 对于结果2,我们可以在(1)的基础上这样解释,当b2刚休眠的时候b1就将money的余额相减然后直接输出,也就没等到和b2一起输出,所以就会是这样的结果
>使用synchronized去模拟取钱的情况
public class BankDem0 {
public static void main(String[] args) {
Bank bank = new Bank();
BankThread b1 = new BankThread(bank);//模拟存折取款
b1.start();
BankThread b2 = new BankThread(bank);//模拟ATM机取款
b2.start();
}
}
class BankThread extends Thread{
private Bank bank = null;
public BankThread(Bank bank) {
this.bank = bank;
}
@Override
public void run() {
System.out.println("取款"+bank.getMoney(400));//设置取款金额为500
}
}
class Bank{
private int money = 500;
public synchronized int getMoney(int number) {
if(number < 0) {//判断取款金额是否正确
return -1;
}else if(money < 0) {//判断账户里面的余额是否正确
return -2;
}else if(number > money) {//判断取款金额是否超过存折里面的金额
return -3;
}else {
try {
Thread.sleep(1000);//休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
money-=number;//取钱之后存款的余额
System.out.println("余额"+money);//输出余额
return number;
}
}
>输出结果
余额100
取款-3
取款400
>结果分析
当一个线程去调用同步方法的时候,这个线程就获取了当前对象的锁,而其他线程去调用同步方法的时候只能等待,因为无法获取对象的锁,因此只能等待第一个线程释放对象的锁方可进入。
例如第一次取了400余额剩余100,第二次再去取钱因为number>money 所以返回-3