35.无锁(乐观锁)CAS

加锁的方式保护共享资源现成安全

public class AccountDemo {
    public static void main(String[] args) {
        Account account = new AccountUnsafe(10000);
        Account.demo(account);
    }
}

class AccountUnsafe implements Account {

    private Integer balance;

    public AccountUnsafe(Integer balance) {
        this.balance = balance;
    }

    //对共享变量的读操作加锁
    @Override
    public Integer getBalance() {
        synchronized (this) {
            return this.balance;
        }
    }

    //给共享变量的写操作加锁
    @Override
    public void withDraw(int amont) {
        synchronized (this) {
            this.balance -= amont;
        }
    }
}

interface Account {

    //获取余额
    Integer getBalance();

    //取款
    void withDraw(int amont);

    static void demo(Account account) {
        //定义一个线程集合
        List<Thread> ts = new ArrayList<>();
        long start = System.nanoTime();
        //创建一千个线程,每个线程取出10元
        for (int i = 0; i < 1000; i++) {
            ts.add(new Thread(() -> account.withDraw(10)));
        }
        //启动每一个线程
        ts.forEach( e -> e.start());
        //等所有线程执行完毕
        ts.forEach( e -> {
            try {
                e.join();
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        });
        long duration = System.nanoTime() - start;
        System.out.println("花费时长:"+duration);
        System.out.println("余额:"+ account.getBalance());
    }
}

无锁,不加锁保证共享资源的线程安全性,使用AtomicInteger类

class AccountUnsafe implements Account {

    //使用AtomicInteger
    private AtomicInteger balance;

    public AccountUnsafe(Integer balance) {
        this.balance = new AtomicInteger(balance);
    }

    @Override
    public Integer getBalance() {
        //AtomicInteger的get方法没有加锁
        return balance.get();
    }

    @Override
    public void withDraw(int amont) {
        while(true) {
            //获取修改前的余额
            int oldVal = this.balance.get();
            //得到修改后的余额
            int newVal = oldVal - amont;
            //修改为新余额之前,要判断是否跟旧余额一致
            //AtomicInteger的compareAndSet方法没有枷锁
            if(balance.compareAndSet(oldVal, newVal)) {
                break;
            }
            //否则进入下一次循环
        }

    }
}

使用AtomicInteger提供的方法,进一步简化代码如下:

@Override
    public void withDraw(int amont) {
        balance.addAndGet(-1 * amont);
        //这里等价于下面注释的代码内容
/*
        while(true) {
            //获取修改前的余额
            int oldVal = this.balance.get();
            //得到修改后的余额
            int newVal = oldVal - amont;
            //修改为新余额之前,要判断是否跟旧余额一致
            //AtomicInteger的compareAndSet方法没有枷锁
            if(balance.compareAndSet(oldVal, newVal)) {
                break;
            }
            //否则进入下一次循环
        }
*/

    }

compareAndSet方法简称CAS,Compare And Swap比较并交换,它必须是原子操作。

compareAndSet方法是原子的,不可分割的。是在cpu的指令集中实现其原子性。

CAS必须得到volatile的支持,因为比较并交换,每次都需要读取共享变量最新的值来实现比较。

CAS的效率比synchronized的效率更高。

无锁的情况下,即使重试失败,线程始终在高速运行,没有停歇。而synchronized会让线程在没有获得锁的时候,发生上下文切换,进入阻塞。

CAS适合的场景,线程数较少,多核cpu的场景

CAS的线程数不要多于cpu的核心数。

CAS是基于乐观锁的实现,最乐观的估计,不怕别的线程来修改共享变量,就算改了也没有关系,我吃点亏再重试。

synchronized是基于悲观锁的实现,防着其他线程来修改共享变量,我上了锁你们都别改,我改完解开锁,你们才有机会。

CAS体现的无锁并发,无阻塞并发。

1.因为没有使用synchronized,所以线程不会陷入阻塞,这是效率提升的因素之一。

2.如果竞争激烈,可以想到重试必然频繁发生,反而效率受到影响。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卷土重来…

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值