在线客服
扫描二维码
下载博学谷APP扫描二维码
关注博学谷微信公众号
Java原子操作之CAS,CAS(Compare and Swap),即比较并替换,是用于实现多线程同步的原子指令。
1. 无锁的概念
在谈论无锁概念时,总会关联起乐观派与悲观派,对于乐观派而言,他们认为事情总会往好的方向发展,总是认为坏的情况发生的概率特别小,可以无所顾忌地做事,但对于悲观派而言,他们总会认为发展事态如果不及时控制,以后就无法挽回了,即使无法挽回的局面几乎不可能发生。
这两种派系映射到并发编程中就如同加锁与无锁的策略,即加锁是一种悲观策略,无锁是一种乐观策略,因为对于加锁的并发程序来说,它们总是认为每次访问共享资源时总会发生冲突,因此必须对每一次数据操作实施加锁策略。而无锁则总是假设对共享资源的访问没有冲突,线程可以不停执行,无需加锁,无需等待,一旦发现冲突,无锁策略则采用一种称为CAS的技术来保证线程执行的安全性,这项CAS技术就是无锁策略实现的关键,下面我们进一步了解CAS技术的奇妙之处。
2. 什么是CAS
CAS(Compare and Swap),即比较并替换,是用于实现多线程同步的原子指令。
执行函数:CAS(V,E,N)
其包含3个参数
• V表示要更新的变量
• E表示预期值
• N表示新值
假定有两个操作A和B,如果从执行A的线程来看,当另一个线程执行B时,要么将B全部执行完,要么完全不执行B,那么A和B对彼此来说是原子的。
实现原子操作可以使用锁,锁机制,满足基本的需求是没有问题的了,但是有的时候我们的需求并非这么简单,我们需要更有效,更加灵活的机制,synchronized关键字是基于阻塞的锁机制,也就是说当一个线程拥有锁的时候,访问同一资源的其它线程需要等待,直到该线程释放锁,
这里会有些问题:首先,如果被阻塞的线程优先级很高很重要怎么办?其次,如果获得锁的线程一直不释放锁怎么办?(这种情况是非常糟糕的)。还有一种情况,如果有大量的线程来竞争资源,那CPU将会花费大量的时间和资源来处理这些竞争,同时,还有可能出现一些例如死锁之类的情况,最后,其实锁机制是一种比较粗糙,粒度比较大的机制,相对于像计数器这样的需求有点儿过于笨重。
实现原子操作还可以使用当前的处理器基本都支持CAS的指令,只不过每个厂家所实现的算法并不一样,每一个CAS操作过程都包含三个运算符:一个内存地址V,一个期望的值A和一个新值B,操作的时候如果这个地址上存放的值等于这个期望的值A,则将地址上的值赋为新值B,否则不做任何操作。
CAS的基本思路就是,如果这个地址上的值和期望的值相等,则给其赋予新值,否则不做任何事儿,但是要返回原值是多少。循环CAS就是在一个循环里不断的做cas操作,直到成功为止。
CAS是怎么实现线程的安全呢?语言层面不做处理,我们将其交给硬件—CPU和内存,利用CPU的多处理能力,实现硬件层面的阻塞,再加上volatile变量的特性即可实现基于原子操作的线程安全。
3. CPU指令对CAS的支持
或许我们可能会有这样的疑问,假设存在多个线程执行CAS操作并且CAS的步骤很多,有没有可能在判断V和E相同后,正要赋值时,切换了线程,更改了值。造成了数据不一致呢?答案是否定的,因为CAS是一种系统原语,原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。
4. 悲观锁,乐观锁
说到CAS,不得不提到两个专业词语:悲观锁,乐观锁。我们先来看看什么是悲观锁,什么是乐观锁。
4.1 悲观锁
顾名思义,就是比较悲观的锁,总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。
4.2 乐观锁
反之,总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。我们今天讲的CAS就是乐观锁。
由于CAS操作属于乐观派,它总认为自己可以成功完成操作,当多个线程同时使用CAS操作一个变量时,只有一个会胜出,并成功更新,其余均会失败,但失败的线程并不会被挂起,仅是被告知失败,并且允许再次尝试,当然也允许失败的线程放弃操作。基于这样的原理,CAS操作即使没有锁,同样知道其他线程对共享资源操作影响,并执行相应的处理措施。同时从这点也可以看出,由于无锁操作中没有锁的存在,因此不可能出现死锁的情况,也就是说无锁操作天生免疫死锁。
5. CAS 的优点
非阻塞的轻量级乐观锁, 通过CPU指令实现, 在资源竞争不激烈的情况下性能高, 相比synchronize重量级悲观锁, synchronize有复杂的加锁, 解锁和唤醒线程操作.。
— 申请免费试学名额 —
在职想转行提升,担心学不会?根据个人情况规划学习路线,闯关式自适应学习模式保证学习效果
讲师一对一辅导,在线答疑解惑,指导就业!
相关推荐 更多
Docker开发教程学习资源
Docker开发教程学习资源,需要学习Docker概览、Docker版本与安装介绍、Docker核心技术之镜像、Docker核心技术之容器、Docker核心技术之容器与镜像、Docker核心技术之数据卷、Docker核心技术之仓库、Docker核心技术之Dockerfile、Docker核心技术之Docker-Compose。
4646
2019-11-11 19:14:44
Java并发与线程免费课程推荐
Java并发与线程免费课程推荐,Java开发中涉及线程的基础知识、线程的启动与终止、线程间的互斥处理与协作、线程的应用、线程的数量管理以及性能优化等内容。
4258
2019-12-03 15:07:22
WEB开发中安全漏洞的分析和预防
随着互联网技术的高速发展,网络安全日益成为大家关注的重点问题,而信息安全方面的人才更是就业市场上的稀缺资源。毫不夸张的说,目前信息安全已经上升到了国家战略的高度,企业对信息安全方面的人才更是求贤若渴。因此掌握安全漏洞的分析和预防是一项极为有用的技能,本文将和大家详细分享WEB开发中常见安全漏洞分析与预防策略。
5070
2020-01-14 11:36:34
数据结构应该怎么学?有哪些建议?
随着计算机科学和互联网技术的日新月异,越来越多的人选择投身于程序员这一职业。尤其是目前的市场中高端的程序员,还处于巨大的人才缺口之中。而低端程序员和中高端程序员一个显著的差别就是,数据结构这一内功掌握得怎么样。那么可能会有人问了:数据结构应该怎么学?有哪些建议呢?下面我们就来看看具体的学习方法。
6283
2020-02-14 19:11:18
Java开发线程特点基础知识分享
线程提供的一些不太常用的方法及技术不管是初学者还是高级用户或者是Java专家都需要了解。掌握线程、进程、多线程、并发、并行、同步、异步、线程类常见方法、线程生命周期、线程安全问题、死锁、生产者和消费者等多线程核心知识点。
3335
2021-05-21 17:07:26