通过模拟取钱过程演示线程安全问题。
一般取钱过程:
- 用户输入账户、密码,系统判断用户的账户、密码是否匹配。
- 用户输入取款金额。
- 系统判断账户余额是否大于取款金额。
- 如果余额大于取款金额,则取款成功;如果余额小于取款金额,则取款失败。
在模拟过程中就模拟后面三步,没有模拟账户密码验证过程。
创建一个账户
创建一个取钱用户,且继承Thread创建线程类
再创建模拟取钱主方法
我们先测试一下查看结果:
很明显张三和李四都成功取出了说明多线程环境下容易出现线程安全问题。
那么来解决多线程安全问题,我目前学习了三种解决多线程安全问题的方法
第一种:使用同步代码块
为了解决线程安全问题,Java的多线程支持引入了同步监视器来解决这个问题,使用同步监视器的通用
方法就是同步代码块。
执行:
锁对象可以是任意对象,但必须保证是同一对象。当其他的线程执行到此时该锁对象已经上锁了,所以就不能再往下执行,就在此等待,只有当第一个线程执行完成后释放该锁,第二个线程再能进入执行,当第二个进入之后同理对该锁对象已经上锁。
第二种:使用同步方法
除了同步代码块,Java的多线程安全支持还提供了同步方法,同步方法也是使用synchronized关键字来
修饰某个方法,则该方法称为同步方法。对于synchronized修饰的实例方法(非static方法),无须显
式指定同步监视器,同步方法的同步监视器就是this,也就是调用该方法的对象。
执行:
第三种:使用同步锁(Lock)
从Java5开始,Java提供了一种功能更强大的线程同步机制——通过显式定义同步锁对象来实现同步,在
这种机制下,同步锁由Lock对象充当。
Lock提供了比synchronized方法和synchronized代码块更广泛的锁定操作,Lock允许实现更灵活的结
构,可以具有差别很大的属性。
Lock是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问,每次只能有
一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。
在实现线程安全的控制中,比较常用的是 ReentrantLock(可重入锁)。使用该Lock对象可以显式地加
锁、释放锁。



