线程安全
多个线程,同时操作同一个共享资源的时候,可能出现业务安全问题。
线程安全问题出现的原因?
①存在多个线程同时执行
②同时访问一个共享资源
③修改共享资源
线程同步
线程同步是解决线程安全问题的方法
解决思路是:让多个线程依次访问共享资源
线程同步常见方案
加锁:每次只允许一个线程加锁,加锁后才能进入访问,访问完毕后自动解锁,然后其他线程才能再加锁进来。
1.同步代码块
作用:把访问共享资源的核心代码给上锁,以此保证线程安全
原理:每次只允许一个线程加锁后进入,执行完毕后自动解锁,其他线程才可以进来执行
对于当前同时执行的线程来说,同步锁必须是同一把(同一个对象)
public void drawMoney(double cash) {
String name = Thread.currentThread().getName();
System.out.println(name + "来取" + cash + "钱");
//this正好代表共享资源
synchronized (this) {
if(this.money>=cash){
System.out.println(name + "取钱成功");
this.money -= cash;
System.out.println(name + "取钱成功" + ",余额为" + this.money);
}else {
System.out.println("余额不足,取钱失败");
}
}
}
锁对象的实用规范
建议实用共享资源作为锁对象,对于实例方法建议实用this作为锁对象
对于静态方法建议实用字节码对象作为锁对象
2.同步方法
作用:把访问共享资源的核心方法给上锁,以此保证线程安全
public synchronized void drawMoney(double cash) {
String name = Thread.currentThread().getName();
System.out.println(name + "来取" + cash + "钱");
if(this.money>=cash){
System.out.println(name + "取钱成功");
this.money -= cash;
System.out.println(name + "取钱成功" + ",余额为" + this.money);
}else {
System.out.println("余额不足,取钱失败");
}
}
同步方法底层原理
同步方法其实底层也是有隐式锁对象的,只是锁的范围是整个方法代码
如果方法是实例方法:同步方法默认用this作为的锁对象
如果方法是静态方法:同步方法默认用类名.class作为锁对象
3.lock锁
lock锁是JDK5开始提供的一个新的锁操作,通过它可以创建出锁对象进行加锁和解锁,更灵活,更方便,更强大。
lock是接口,不能直接实例化,可以采用它的实现类ReentrantLock来构建Lock锁对象
private final Lock lock = new ReentrantLock();
public void drawMoney(double cash) {
String name = Thread.currentThread().getName();
System.out.println(name + "来取" + cash + "钱");
lock.lock();//加锁
try {
if(this.money>=cash){
System.out.println(name + "取钱成功");
this.money -= cash;
System.out.println(name + "取钱成功" + ",余额为" + this.money);
}else {
System.out.println("余额不足,取钱失败");
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
lock.unlock();//解锁
}