CAS 悲观锁 乐观锁

前面的偏向锁,轻量级锁,重量级锁都是悲观锁,

都会认为必须要对操作对象进行互斥访问,不然就会产生异常, 所以线程只供一个线程使用,阻塞其他线程,是悲观的

在某些情况下,同步的耗时远大于线程切换的时间,互斥就有点多余了

纸飞机APP

所以使用CAS compare ans swap

一个资源 对应一个 tig 为1表示被占用,0表示未被占用

两个线程(称为AB) 均想获取该资源,即都希望当前tig为0 并由自己将其置为1

用代码表示: 逻辑就是这样的

intcas(long* address,long oldValue,long newValue)
{
  if(*address!=oldValue){
    return0;
  }
  *address = newValue;
  return1;
  
}

如果csa失败 则等待。

如果只看代码 同样也是无法实现互斥的,代在底层,我们的CAS 是原子性 的。比较和交换两个操作是一体的。

还有就是底层的循环等待一般也不是死循环,是有限制的

Java中的使用示例:

不使用CAS:

publicclassMain {

    publicstaticvoidmain(String[] args) {

        int i;
        for (i = 0; i < 4; i++) {
            newcasTest().start();
        }
    }
}

classcasTestextendsThread{
    publicstaticinta=0;

    @Overridepublicvoidrun() {
        while(a<1000){
            System.out.println(getName() + "   "+a++);
            try {
                sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

输出:

Thread-0993
Thread-2994
Thread-1995
Thread-3996
Thread-0997
Thread-1998----
Thread-2998----
Thread-0999
Thread-3999

只截了最后几行

可以看到 标记处 两个线程输出了同样的数

代码线程不安全

下面我们尝试使用互斥锁

publicclassMain {

    publicstaticvoidmain(String[] args) {

        int i;
        for (i = 0; i < 4; i++) {
            newcasTest().start();
        }


    }
}


classcasTestextendsThread{
    publicstaticinta=0;

    @Overridepublicvoidrun() {
        while(a<1000){
            System.out.println(getName() + "   "+a++);
            synchronized (Math.class){
                a++;
            }

        }


    }
}

输出:

Thread-2982
Thread-2984
Thread-2986
Thread-2988
Thread-2990
Thread-2992
Thread-2994
Thread-2996
Thread-2998
Thread-1502
Thread-0586

无重复

下面我们用 CAS:

import java.util.concurrent.atomic.AtomicInteger;

publicclassMain {

    publicstaticvoidmain(String[] args) {

        int i;
        for (i = 0; i < 4; i++) {
            newcasTest().start();
        }


    }
}

classcasTestextendsThread{
//    public static int a = 0;publicstaticAtomicIntegerinteger=newAtomicInteger(0);

    @Overridepublicvoidrun() {
        while(integer.get()<1000){
            System.out.println(getName() + "   "+integer.incrementAndGet());

        }


    }
}

输出:

Thread-1993
Thread-1994
Thread-1995
Thread-1996
Thread-1997
Thread-0960
Thread-0999
Thread-01000
Thread-2943
Thread-1998

顺序不同是因为输出的缘故

但不会出现重复,即实现了互斥

下面点进去看看源码:

确实用的是CAS

再往下一点:

这里是native方法

不同系统的代码可能不同,都是基于本地硬件进行CAS操作 c++实现

找到了一个源码的截图:

框框处调用了汇编命令

### CAS机制属于乐观锁 CAS(Compare and Swap)作为一种并发控制方法,确实归属于乐观锁范畴[^2]。乐观锁假设对共享资源的访问通常是没有竞争的,因此线程可以在不加锁也不等待的情况下持续运行。 #### Compare and Swap (CAS) 的工作原理 CAS的核心在于通过比较并交换的方式,在多线程环境下安全地更新变量值: ```java public class AtomicExample { private static AtomicInteger atomicInt = new AtomicInteger(0); public void safeIncrement() { int expected; do { expected = atomicInt.get(); } while (!atomicInt.compareAndSet(expected, expected + 1)); } } ``` 这段代码展示了如何利用`compareAndSet()`函数实现原子性的自增操作。此函数会检查当前值是否等于预期值,如果是则设置新的值;如果不是,则返回失败,并允许调用者决定下一步动作。 #### 乐观锁悲观锁的区别 | 特征 | 乐观锁 | 悲观锁 | |-------------|--------------| | 基本理念 | 认为数据冲突概率低,只有在提交更改时才检测是否有冲突发生 | 预期会有较多的数据争用情况,所以在整个事务期间都持有锁定 | | 性能影响 | 减少了不必要的锁定开销,提高了程序效率 | 锁定可能会降低系统吞吐量,特别是在高并发场景下 | | 应用场景示例 | 社交媒体平台上的阅读计数器等读远超写的场合 | 数据库管理系统中频繁修改记录的情形 | 乐观锁适合于那些大多数情况下不存在并发写入的应用场景,而悲观锁更适合处理存在较高频率并发写入的情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值