基于Synchronized和Lock实现的同步锁机制,属于悲观锁,保护线程安全最直观的方式。

悲观锁在高并发场景下,激烈的锁竞争会造成线程阻塞,大量阻塞线程会导致系统的上下文切换,增加系统的性能开销。

乐观锁:在操作共享资源时,总是抱着乐观的态度执行,认为自己可以成功的完成操作;但当多个线程同时操作一个共享资源时,只有一个线程会成功,而失败的线程不会像悲观锁一样在操作系统中挂起,而仅仅是返回,并且系统允许失败的线程重试,也允许自动放弃退出操作。

所以,乐观锁相对悲观锁来说,不会带来死锁、饥饿等活性故障问题,线程间的相互影响也远远比悲观锁小;乐观锁没有因竞争造成的系统开销,在性能上也更胜一筹。

乐观锁的实现原理

CAS是实现乐观锁的核心算法,它包含了三个参数:共享变量的内存地址A、用于比较的值B、共享变量的新值C;只有当内存地址A处的值等于B时,才能将内存地址A处的值更新为新值C。作为一条CPU指令,CAS指令本身是能够保证原子性的。

CAS如何实现原子操作?

在JDK的concurrent包中,atomic路径下的类都是基于CAS实现的;

AtomicInteger依赖于本地方法Unsafe类,Unsafe中的操作方法会调用CPU底层指令实现原子操作。

//基于CAS操作更新值
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
    //基于CAS操作增1
    public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }
    
    //基于CAS操作减1
    public final int getAndDecrement() {
        return unsafe.getAndAddInt(this, valueOffset, -1);

处理器如何实现原子操作?

处理器和物理内存之间的速度远慢于处理器之间的速度,所以处理器有自己的内部缓存。

频繁使用的内存数据会缓存在处理器的L1、L2和L3的高级缓存中,以加快频繁读取的速度。

python 乐观锁实现 乐观锁的实现原理_并发编程

一般情况下,一个单核处理器能够自我保证基本的内存操作是原子性的,当一个线程读取一个字节时,所有进程和线程看到的字节都是同一个缓存里的字节,其他线程不能访问这个字节的内存地址。

但现在的服务器通常是多处理器,且每个处理器都是多核的,每个处理器维护了一块字节的内存,每个内核维护了一块字节的缓存,这时候多线程并发就会存在缓存不一致的问题,从而导致数据不一致。

此时,处理器提供了总线锁定缓存锁定两个机制来保证复杂内存操作的原子性。

当处理器要操作一个共享变量时,会在总线上发出一个Lock信号,这时其他处理器就不能操作共享变量了,该处理器会独享此共享内存中变量。但总线锁定在阻塞其他处理器获取该共享变量的操作请求时,也可能会导致大量阻塞,从而增加系统的性能开销。

由此,后来的处理器采取了缓存锁定机制,当某个处理器对缓存中的共享变量进行了操作,就会通知其他处理器放弃存储该共享资源或者重新读取该共享资源。