本文已参与「新人创作礼」活动,一起开启掘金创作之路。
Synchronized基本概念
先了解几个术语:
- 临界区: 指的是某⼀块代码区域块,它同⼀时刻只能由⼀个线程执⾏。
- 竞态条件:对共享内存的进行竞争读写的地方
- CAS(Compare and Swap ): 比较并交换,⽤于在硬件层⾯上提供原子性操作。 乐观锁就是用到了CAS
CAS
下面介绍CAS实现原子操作的两大问题
- ABA问题:ABA问题就是⼀个值原来是A,变成了B,⼜变回了A。这个时候使⽤CAS是 检查不出变化的,但实际上却被更新了两次。 解决思路是使用“版本号”或者加上时间戳(JUC的atom包有响应的工具类可以使用)
- 自旋开销大: CAS多与自旋结合。如果⾃旋CAS⻓时间不成功,会占⽤⼤量的CPU资源。 解决思路是让JVM⽀持处理器提供的pause指令, pause指令能让⾃旋失败时cpu睡眠⼀⼩段时间再继续自旋。
CAS+volatile实现无锁
class AccountSafe implements Account {
private AtomicInteger balance; // 原子整数,用volatile实现的
public AccountSafe(Integer balance) {
this.balance = new AtomicInteger(balance);
}
@Override
public Integer getBalance() {
return balance.get();
}
@Override
public void withdraw(Integer amount) {
while (true) {
int prev = balance.get();
int next = prev - amount;
if (balance.compareAndSet(prev, next)) { // cas
break;
}
}
// 可以简化为下面的方法
// balance.addAndGet(-1 * amount);
}
}
- CAS必须借助volatile才能读取到共享变量的最新值来实现【比较并交换】的效果
Synchronized使用
// 关键字在实例⽅法上,锁为当前实例
public synchronized void instanceLock() {
// code
}
// 关键字在静态⽅法上,锁为当前Class对象
public static synchronized void classLock() {
// code
}
// 关键字在代码块上,锁为括号⾥⾯的对象
public void blockLock() {
Object o = new Object();
synchronized (o) {
// code
}
}
Synchronized实现原理
synchronized关键字的实现,依赖于Java的对象头中的Mark Word
Mark Word具体字段:
- 默认存储对象的 HashCode、分代年龄、偏向模式以及锁标志位