场景:
一个人在一家银行办了一个账户,银行给了 一张卡(存取款)、一本存折(存取款)、一个网银(查询余额)
卡和存储不断存款和取款,网银不断查询余额。如何保持余额的正确。
例子(线程不安全):
控制器代码:
@Controller
public class TestController {
// 开个银行帐号
Acount3 account = new Acount3();
@RequestMapping(value="/cardAddAcount")
@ResponseBody
public TaotaoResult<Integer> cardAddAcount(){
TaotaoResult<Integer> result = new TaotaoResult<Integer>();
result.setData("+100, 余额: " + account.addAcount("card", 100));
return result;
}
@RequestMapping(value="/passbookAddAcount")
@ResponseBody
public TaotaoResult<Integer> passbookAddAcount(){
TaotaoResult<Integer> result = new TaotaoResult<Integer>();
result.setData("+100, 余额: " + account.addAcount("存折", 100));
return result;
}
@RequestMapping(value="/cardSubAcount")
@ResponseBody
public TaotaoResult<Integer> cardSubAcount(){
TaotaoResult<Integer> result = new TaotaoResult<Integer>();
result.setData("-150, 余额: " + account.subAcount("card", 150));
return result;
}
@RequestMapping(value="/passbookSubAcount")
@ResponseBody
public TaotaoResult<Integer> passbookSubAcount(){
TaotaoResult<Integer> result = new TaotaoResult<Integer>();
result.setData("-200, 余额: " + account.subAcount("存折", 200));
return result;
}
@RequestMapping(value="/selectAcount")
@ResponseBody
public TaotaoResult<Integer> selectAcount(){
TaotaoResult<Integer> result = new TaotaoResult<Integer>();
result.setData(account.selectAcount(""));
return result;
}
}
账户3(线程不安全):
/**
* 银行账户:无任何并发处理
*
* @author Administrator
*/
public class Acount3 {
private int count = 0;
/**
* 存钱
*
* @param money
*/
public int addAcount(String name, int money) {
// 存钱
count += money;
System.out.println(name + "...存入:" + money + "..." + Thread.currentThread().getName());
return selectAcount(name);
}
/**
* 取钱
*
* @param money
*/
public int subAcount(String name, int money) {
// 先判断账户现在的余额是否够取钱金额
if (count - money < 0) {
System.out.println("账户余额不足!余额=" + count);
return money;
}
// 取钱
count -= money;
System.out.println(name + "...取出:" + money + "..." + Thread.currentThread().getName());
return selectAcount(name);
}
/**
* 查询余额
*/
public int selectAcount(String name) {
System.out.println(name + "...余额:" + count);
return count;
}
}
账户3(线程不安全)执行的结果:
例子2:
账户2(线程安全):给每个方法加上synchronized 实现
/**
* 银行账户:线程安全
*
* @author Administrator
*/
public class Acount2 {
private int count = 0;
/**
* 存钱
*
* @param money
*/
public synchronized int addAcount(String name, int money) {
// 存钱
count += money;
System.out.println(name + "...存入:" + money + "..." + Thread.currentThread().getName());
return selectAcount(name);
}
/**
* 取钱
*
* @param money
*/
public synchronized int subAcount(String name, int money) {
// 先判断账户现在的余额是否够取钱金额
if (count - money < 0) {
System.out.println("账户余额不足!余额=" + count);
return money;
}
// 取钱
count -= money;
System.out.println(name + "...取出:" + money + "..." + Thread.currentThread().getName());
return selectAcount(name);
}
/**
* 查询余额
*/
public synchronized int selectAcount(String name) {
System.out.println(name + "...余额:" + count);
return count;
}
}
例子1:
账户1(线程安全):通过lock来实现
import java.util.concurrent.locks.ReentrantLock;
/**
* 银行账户:线程安全
*
* @author Administrator
*/
public class Acount {
private int count = 0;
private ReentrantLock lock = new ReentrantLock();
/**
* 存钱
*
* @param money
*/
public int addAcount(String name, int money) {
lock.lock();
try {
// 存钱
count += money;
System.out.println(name + "...存入:" + money + "..." + Thread.currentThread().getName());
} finally {
lock.unlock();
}
return selectAcount(name);
}
/**
* 取钱
*
* @param money
*/
public int subAcount(String name, int money) {
lock.lock();
try {
// 先判断账户现在的余额是否够取钱金额
if (count - money < 0) {
System.out.println("账户余额不足!余额=" + count);
return money;
}
// 取钱
count -= money;
System.out.println(name + "...取出:" + money + "..." + Thread.currentThread().getName());
} finally {
lock.unlock();
}
return selectAcount(name);
}
/**
* 查询余额
*/
public int selectAcount(String name) {
lock.lock();
try {
System.out.println(name + "...余额:" + count);
} finally {
lock.unlock();
}
return count;
}
}
代码demo:
链接:https://pan.baidu.com/s/1i_uzZKd-GC-8NPa1hFdw8w 密码:rht7
测试用例:
链接:https://pan.baidu.com/s/1Ri54rR1k7JETO6i5pDyVlw 密码:u96e