CAS和Synchronized

it2026-04-22  3

CAS

CAS(compare and sawp)比较并且交换,是一种实现线程安全的无锁技术。在我们多线程情况下对一个变量进行修改时,首先要保证该变量的可见性,就要使用volatile关键字来修饰该变量,在修改该变量之前会先读取一下,计算一下得到修改后的预期值,然后进行CAS把读取的变量值修改为预期值,这一步操作是原子性的,所以如果读取值发生了变化,就会返回false,这样就可以一直while循环去修改值。看一下jdk中AtomicInteger.getAndIncrement()方法:

public final int getAndIncrement() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return current; } }

CAS导致的ABA问题:意思是当我们去修改一个值时,另一个线程也去修改这个值,但是修改完之后又修改了回来。解决ABA问题,可以对这个变量加一个版本号,每次修改一下就改变一下版本号,这样当CAS时版本号不一样也会失败。

再说一下CAS为什么是原子性的,底层用的是 lock cmpxchg指令,就是会对这条指令进行加锁。

Synchronized

synchronized关键字能保证我们的同步代码块在多线程的情况下串行执行,保证了线程安全。

synchronized早期是一把重量级锁,为什么说是重量级呢,因为使用的是操作系统中的monitor完成的,这样就牵扯到用户态切内核态,造成了性能开销。但有些场景下是不需要使用moniter就可以保证线程安全,比如说CAS,但是如果频繁使用CAS的话,会大大提升cpu的压力,所以会有一个锁升级的过程。

因为synchronized要使用对象进行加锁,就要提一下oop模型,oop是java对象在jvm中的存在形式,它有对象头,实例数据,对齐填充组成。对象头中又包含三部分 :Mark word,类型指针,数组长度。这里我们重点说一下Mark word。Mark word主要存放的是锁信息,GC信息,HashCode。

Mark word在64位虚拟机中占8个字节

无锁:没有执行同步代码块时,此时对象是无锁状态。锁标志位是01

偏向锁:当首次进入同步代码块时,会将该对象的偏向锁的线程ID置为当前线程ID,并设置偏向锁标志位为1

轻量级锁:当存在线程竞争锁时,会撤销偏向锁,升级为轻量级锁,锁标志位设置为00,然后各个线程通过CAS获取锁,允许短时间内锁竞争

重量级锁:当对象是轻量级锁是,各个线程通过CAS获取锁,当达到一定次数时,会升级成重量级锁,jdk内部实现的自适应自旋操作。

最新回复(0)