Lock锁之CAS

谈论锁就离不开CAS,CAS是compare and swap的缩写,从字面上理解就是比较并更新;主要是通过 处理器的指令 来保证操作的原子性

简单来说:程序先要得到一个值A,这个值正常就是从我们要更新的内存位置得到的,进行CAS操作的时候,我们需要传入两个值,一个是A,一个是我们要修改的值B,此时才正式进入原子操作

从内存位置V上取到存储的值,将值和预期值A进行比较,如果值和预期值A的结果相等,那么我们就把新值B更新到内存位置V上,如果不相等,那么就重复上述操作直到成功为止。

CAS是一种无锁化编程,是一种非阻塞的轻量级的乐观锁;而synchronized是阻塞式的重量级悲观锁

CAS实现

下面是AtomicInteger类里一个更新值的方法

    public final int updateAndGet(IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(prev, next));
        return next;
    }

这里的get()是获取要操作的值,next就是要更新的值,compareAndSet就是上面说的CAS操作,底层是native方法,他可以保证操作的原子性,当操作不符合预期(即A与V不相等,或者说prev与操作时候读出来的V不相等),就会返回false,然后这个操作就会一致循环,直到成功,他的value也是用volatile修饰的,保证修改可见(不然有可能get出来的值一直是旧值,这样就变成死循环了)

CAS+Volatile= 同步代码块

通过CAS+Volatile关键字,我们可以实现一个乐观锁,来完成同步操作

Volatile用于修饰一个标志位,可以理解为标志一个锁是否被占有,通过Volatile关键字我们可以保证所有线程都可以访问到这个标志位最新的值,CAS主要用于完成原子操作

实现步骤

  1. 使用 volatile 关键字修饰一个int类型的同步标志位state,初始值为0;
  2. 加锁/释放锁时使用CAS操作对同步标志位state进行更新; 加锁成功,同步标志位值为 1,加锁状态; 释放锁成功,同步标志位值为0,初始状态;

参考加锁代码

 /**
 * 加锁,非公平方式获取锁
 */
public final void lock() {

    while (true) {
        // CAS操作更新同步标志位
        if (compareAndSetState(0, 1)) {
            // 将独占锁的拥有者设置为当前线程
            exclusiveOwnerThread = Thread.currentThread();

            System.out.println(Thread.currentThread() + "  lock success ! set lock owner is current thread .  " +
                    "state:" + state);

            try {
                // 睡眠一小会,模拟更加好的效果
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            // 跳出循环
            break;

        } else {
            // TODO 如果同步标志位是1,并且锁的拥有者是当前线程的话,则可以设置重入
            if (1 == state && Thread.currentThread() == exclusiveOwnerThread) {
                // 进行设置重入锁
            }

            System.out.println(Thread.currentThread() + "  lock fail ! If the owner of the lock is the current thread," +
                    "  the reentrant lock needs to be set;else Adds the current thread to the blocking queue .");

            // 将线程阻塞,并将其放入阻塞列表
            parkThreadList.add(Thread.currentThread());
            LockSupport.park(this);

            // 线程被唤醒后会执行此处,并且继续执行此 while 循环
            System.out.println(Thread.currentThread() + "  The currently blocking thread is awakened !");
        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值