首页 > 编程学习 > Java 各种锁的理解与实现

Java 各种锁的理解与实现

发布时间:2023/3/30 2:03:18

1.  volatile 是轻量级锁:

        只能修饰在变量上,使得 cpu 每次对于该变量的修改和读取都从内存中操作,而不是从CPU cache 中操作,保证共享变量对所有线程的可见性,但是并不能保证原子性

2. synchronized 悲观锁:

        当某个线程访问被 synchronized 修饰的方法或代码块时,会先检查有没有其他线程在占用该对象锁,如果有,则该线程进入阻塞状态,直到占用该锁的线程使用完毕释放锁;synchronized 能够保证同一时刻只能有一个线程能访问,可修饰在类,方法,变量上,保证多线程下操作的可见性和原子性

缺点:由于线程阻塞引起的线程频繁睡眠和唤醒极大的消耗了 CPU 资源

3. CAS 自旋锁:

        当多个线程竞争一个共享资源时,只有一个线程会胜出,但是其它竞争失败的线程并不会放弃占用cpu,而是循环刷新访问对于该资源锁的请求,直到获取该资源的锁;CAS只能保证变量的原子性并不能保证变量的可见性,所以一般都是使用 CAS + Volatile 实现变量的多线程

1)JUC 并发包中的原子类都存放在 java.util.concurrent.atomic 类路径下

2)CAS 原理:
        CAS 内部维护需要读写的内存值(V)、expecValue(A)、newValue(B)

3)简单测试

        可以看到expectValue = 11,newValue = 20,因为内存旧值 = 10,不等于 expectValue,说明在这段时间内有其他线程操作了对象 atomicInteger ,修改了其值,所以本次修改失败,修改结果res = false,atomicInteger.get() = 10

import java.util.concurrent.atomic.AtomicInteger;
public class TestConCurrent {
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(10);

        boolean res = atomicInteger.compareAndSet(11, 20);
        System.out.println("原子对象的修改结果:"+res);

        System.out.println(atomicInteger.get());
    }
}

4)自旋CAS缺点:

  1. 未获得锁的线程如果一直循环执行,会给CPU带来非常大的执行开销
  2. CAS 保证的是对一个变量执行操作的原子性,如果对多个变量操作时,CAS 目前无法直接保证操作的原子性
  3. ABA 问题:当某线程提交操作进行比较时发现内存数据旧数据A和预期值A一致,但是可能该数据被其他线程修改成B,然后又被其他线程修改回A;真正要做到严谨的CAS机制,我们在compare阶段不仅要比较期望值A和地址V中的实际值,还要比较变量的版本号是否一致
Copyright © 2010-2022 mfbz.cn 版权所有 |关于我们| 联系方式|豫ICP备15888888号