标签:工资 恢复 ola 乐观锁 可见 状态 出现 作用 线程安全
为了便于移植,Java 多线程内存模型不与硬件关联,不同硬件平台可以使用不同的实现手段
和 CPU 内存与高速缓存做对比 Java 内存模型被分为两大部分:主内存(对应 PC 内存)和工作内存(对应 CPU 高速缓存)
主内存与工作内存之间数据的交互 Java 定义了以下 8 种原子操作(最新的 Java 标准已经采用了新的内存访问协议,但下面 8 中操作也应该了解一下)
结合上面 8 中操作如果把一个变量从主内存复制到工作内存,那就要顺序执行 read 和 load 操作,Java 内存模型只要求上述两个操作必须按顺序执行(且不能单独出现 read 或 load,同理 write 和 store),没有要求连续执行,即这两个操作之间可以插入其他指令
volatile 变量和 C/C++ 中的概念是一致的,有以下两个特点
Java 内存模型要求 lock 等 8 个变量操作都具有原子性,但对 64 位数据类型却定义了比较宽松的规定:允许虚拟机将没有被 volatile 修饰的数据读写操作分为两次 32 位的操作来运行。这就导致了多线程非同步情况下读到半个变量的可能性 ,不过大部分商用虚拟机实现都将 64 位数据的操作也实现为原子操作
JDK 1.2 前 Java 的线程使用协程实现,之后使用系统原生线程
互斥是方法,同步是目的。Java 中最基本的互斥同步手段是关键字 synchronized
常见的互斥锁是悲观锁,认为只要使用变量就要上锁,无论变量是否出现了竞争条件。随着 CPU 指令的发展我们可以使用基于冲突检测的并发策略,也就是乐观锁。通俗的讲,先进行操作,如果没有发现竞争就认为操作成功,否则就采取其他补偿措施,比如不断的重试,直到成功为止
线程的挂起与恢复是非常耗时的,如果上锁时间很短,使用自旋锁是非常好的优化手段
自适应自旋锁,自旋的次数按一定的策略动态变化
乐观锁与悲观锁最大的区别是前者会先尝试去修改变量,失败后进行补偿,乐观锁避免了线程的阻塞
乐观锁示例:CAS(Compare And Swap),下面这段代码是 Java 使用 CAS 实现的变量自增,可以用来说明 CAS 的使用方法
public final int incrementAndGet()
{
for(;;)
{
int current = get();
int next = current+1;
if(compareAndSet(current, next)) // 非互斥,设置失败则不断尝试
{
return next;
}
}
}
两个线程分别使用 CAS 实现变量 val 的修改,假设 val 初始值为 val0,线程 A 将 val 修改为 val1 后又修改为 val0,如果在这个过程中线程 B 先读到的是 val0,在修改时 A 已经完成了 val 从 val1 到 val0 的修改过程,val 的状态其实已经发生了变化,但 B 却没有感知到,这个漏洞被称为 ABA。大部分情况下 ABA 对程序的正常运行没有影响
Java 中的轻量级锁是和系统提供的锁相对应的,本意是在没有多线程竞争的前提下减少传统重量级锁的使用,以减少互斥带来的损耗
轻量级锁所依据的前提是:对于绝大部分的锁,在整个同步周期内都是不存在竞争的,所以没必要一定要使用重量级锁
轻量级锁会先尝试使用 CAS 给对象打标记,如果成功就不用调用重量级锁并标记对象已被其他线程占用;而其他线程在使用对象时也会确认对象是否已被占用
在存在竞争的情况下,轻量级锁会比重量级锁耗时
标签:工资 恢复 ola 乐观锁 可见 状态 出现 作用 线程安全
原文地址:https://www.cnblogs.com/jiahu-Blog/p/11824847.html