AQS , CAS 原理

AQS 原理

       AQS 全称 AbstractQuenedSynchronizer。也就是多线程同步器。是并发编程的核心。ReentrantLock 就是 AQS 的一个实现。AQS 有三个特点。

1、AQS 提供了 2 种锁的机制(共享锁和排他锁)。共享锁是可以同时被多个线程所读取,默认为都不会对数据修改。排他锁则是悲观的认为,每个线程都要修改,所以每次只会允许一个线程获取锁。

2、AQS提供了可重入锁,也就是获取到锁资源的线程可以继续获取锁

3、AQS还提供了所公平性和非公平性

AQS 我认为有 2 个比较重要的核心参数

1、State,表示当前锁的状态,0是没有线程占用,1是正在被使用

举例:假设现在有一个线程要获取一个锁。锁是 ReentrantLock。首先使用 lock()方法进行加锁,会把 state 设置为 1,然后将线程名字设置成自己。这样就算获取成功了。ReentrantLock 是一个可重入锁,所以我们要是再次尝试获取这个锁,他会继续判断 state 是否是 0,如果不是,那就继续判断线程名称是不是自己,是的话将 state+1。

2、还有一个是线程名称,表示的是获取到线程的线程名称

举例:假如说 A 线程目前获取了一个锁,B 进来尝试获取,B 发现 state 大于 0 并且线程名字不是自己,那么他会去一个地方进行等待。这个地方叫锁池。A 执行完逻辑后,会释放锁,释放锁会将 state-1。然后判断是否为 0,为 0 的话将线程名称设置为 null。真正释放锁,如果 state 还是>0 就继续执行逻辑,直到完全释放锁。等释放了锁,线程 B 就可以获取锁成功了。

CAS 原理

读取当前这个值,计算结果,比较当前新的这个值,就是原来内存的那个值和我读取到的值是否一致,一致返回 TRUE 将值更新为新值,如果有人变过最初获取到的值,就重新再来获取最新的值进行计算再来比较值,一直循环当前这个操作。

 CAS 的 ABA 问题

通过版本号的方式解决 ABA 的问题,每次执行数据修改操作时,都会带上一个版本号,一旦版本号和数据的版本号一致就可以执行修改操作并对版本号执行+1 操作,否则就执行失败。每次操作的版本号都会随之增加,所以不会出现 ABA 问题,因为版本号只增不减。在 JDK1.5 开始的 atomic 包里提供了一个类,AtomicStampedReference来解决 ABA 的问题。