CAS 悲观锁 乐观锁

时间:2023-02-12 11:09:29

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

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

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

所以使用CAS compare ans swap

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

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

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

int cas(long* address,long oldValue,long newValue)
{
  if(*address!=oldValue){
    return 0;
  }
  *address = newValue;
  return 1;
  
}

如果csa失败 则等待。

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

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

Java中的使用示例:

不使用CAS:

public class Main {

    public static void main(String[] args) {

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

class casTest extends Thread{
    public static int a = 0;

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

输出:

Thread-0   993
Thread-2   994
Thread-1   995
Thread-3   996
Thread-0   997
Thread-1   998----
Thread-2   998----
Thread-0   999
Thread-3   999

只截了最后几行

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

代码线程不安全

下面我们尝试使用互斥锁

public class Main {

    public static void main(String[] args) {

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


    }
}


class casTest extends Thread{
    public static int a = 0;

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

        }


    }
}

输出:

Thread-2   982
Thread-2   984
Thread-2   986
Thread-2   988
Thread-2   990
Thread-2   992
Thread-2   994
Thread-2   996
Thread-2   998
Thread-1   502
Thread-0   586

无重复

下面我们用 CAS:

import java.util.concurrent.atomic.AtomicInteger;

public class Main {

    public static void main(String[] args) {

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


    }
}

class casTest extends Thread{
//    public static int a = 0;
    public static AtomicInteger integer  = new AtomicInteger(0);

    @Override
    public void run() {
        while(integer.get()<1000){
            System.out.println(getName() + "   "+integer.incrementAndGet());

        }


    }
}

输出:

Thread-1   993
Thread-1   994
Thread-1   995
Thread-1   996
Thread-1   997
Thread-0   960
Thread-0   999
Thread-0   1000
Thread-2   943
Thread-1   998

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

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

下面点进去看看源码:
CAS 悲观锁 乐观锁

CAS 悲观锁 乐观锁

确实用的是CAS

再往下一点:
CAS 悲观锁 乐观锁

这里是native方法

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

找到了一个源码的截图:

CAS 悲观锁 乐观锁

框框处调用了汇编命令