1. 何为原子性?
CPU层面一个或者多个操作在 CPU 执行的过程中不被中断的特性,称为 “原子
性”;对于日常使用的编程语言,原子性的解释可以是 多个资源间有一致性的要求,操作的中间状态对外不可见。
long 型变量在 32 位机器上读写可能出现的诡异 Bug,因为 CPU 要进行两次运算,一个写高32位,一次写低32位,在多核CPU的情况下就会出现多个CPU操作同一份数据。如果我们能够保证对共享变量的修改是 互斥 的,那么就能保证原子性。
2. 锁模型保证原子性
我们把一段需要 互斥执行 的代码称为 临界区,线程进入到临界区前尝试对 受保护的资源 进行加锁 lock(),离开临界区执行解锁 unLock()
加锁的原则:1. 注意锁的粒度,如果锁的粒度太粗会影响执行效率。2. 切记注意锁住正确的资源,加锁错误一样会有并发问题
2.1 synchronized锁技术
- 基于Native方法实现,在 JDK1.5 之后得到了大量的优化;单线程访问为偏向锁,减少加锁开销,如果存在线程竞争则升级为轻量级锁,同时抹去偏向锁标识。
- 可以修饰代码块、方法
- 获取锁不可超时、不可中断、会导致线程阻塞(不同于JUC里面的锁),且自身占有的资源不会被释放
- 可变对象不能用于加锁,如下代码
class SafeCalc {
long value = 0L;
long get() {
synchronized (new Object()) {
return value;
}
}
void addOne() {
synchronized (new Object()) {
value += 1;
}
}
}