问题背景
我们都知道Java的多线程运行会存在一些问题,比如我下面列举的一些问题:
- 各个线程是通过竞争CPU时间获得运行机会的
- 各线程什么时候得到CPU时间、占用多久都是随机的
- 一个正在运行着的线程在什么地方被暂停是不确定的
下面我们以银行存取款的一个案例演示这些问题造成的后果!
问题描述
假定公司财务有一张公共的银行卡,这张卡经常性出现同时有人存款、有人取款的现象。这里我们模拟同时存入100元和取出200元的存取款过程 。
下面我们通过代码简单演示一下这个过程,我们新建示例代码如下:
下面我们运行上面的示例代码,发现由于线程数很少,大多数存取款可以正常进行,控制台输出结果为:
当我们多次运行程序代码时,你会发现有可能出现下面的这些情况:
原因分析:
首先,正常情况下我们同时存取进行的操作顺序应该是这样的:
账户余额1000 ------------》存入100元后余额1100元------------》取出200元后余额900元 or 账户余额1000 ------------》取出200元后余额800元------------》存入100元后余额900元
结合上面的异常输出结果我们不难分析原因,存款线程和取款线程有可能在写入数据前运行被终止,就拿我们最后余额为800元的异常来说。系统可能的执行流程如下:
账户余额1000 ------------》存款进程存入100元后余额未写入完毕,CPU资源被抢占,当前余额1000元------------》取款进程取出200元后余额未写入完毕,CPU资源被抢占,当前余额800元------------》存款进程继续将被抢占前的余额写入,当前余额1100元-----------》取款进程继续将被抢占前余额写入,当前余额800元。
解决方案:
线程同步!
- 保证在存取款过程中,不允许其他线程对账户余额进行操作
- 过程中将Bank对象进行锁定
- 使用关键字synchronized实现
public synchronized void saveAccount(){
}
public static synchronized void saveAccount(){
}
synchronized(obj){
}
解决问题:
|