前言
自学了一年JAVA阿巴阿巴终于约到了面试,这次面试官让她谈谈对CAS的了解。
<Center>回去等告诉</Center>
如果对CAS齐全不理解的同学倡议先去看看相干的博客理解了根本的原理,再来看面试的时候如何解答
面试官: 对CAS有理解吗?能够讲讲吗?
阿巴阿巴: 理解一些,CAS全称Compare And Swap,也就是比拟和替换。
阿巴阿巴: CAS的思维比较简单,次要波及到三个值:以后内存值V、预期值(旧的内存值)O、行将更新的内存值U,当且仅当预期值O与以后内存值V相等时,将内存值V批改为更新值U,并返回true,否则返回false。
面试官: 还有嘛?CAS的应用场景晓得吗?
阿巴阿巴: 额...应该差不多了,CAS如同在并发包里应用到了
面试官: 好,CAS有啥毛病吗?
阿巴阿巴: 额....好..如同有个ABA的问题,如同是用AtomicStampedReference解决
面试官: 还有其余毛病吗?
阿巴阿巴: 额...记不太清了....
面试官: 行,那你这边先回去等告诉哈
阿巴阿巴: 好的~
<Center>当场发offer</Center>
面试官: CAS理解吗?讲讲
阿巴阿巴: CAS全称Compare and Swap,也就是比拟和替换。
阿巴阿巴: CAS的思维比较简单,次要波及到三个值:以后内存值V、预期值(旧的内存值)O、行将更新的内存值U,当且仅当预期值O与以后内存值V相等时,将内存值V批改为更新值U,返回true,否则返回false。
阿巴阿巴: CAS次要应用在一些须要上锁的场景充当乐观锁解决方案,个别在一些简略且要上锁的操作但又不想引入锁场景,这时候来应用CAS代替锁。
阿巴阿巴: CAS次要波及到三个问题:ABA问题、自旋带来的耗费、CAS只能单变量
面试官: 能够具体讲一下这三个问题吗?
阿巴阿巴: ABA问题是指有一个线程t1在进行CAS操作时,其余线程t2将变量A改成了B,而后又将其改成A,这时候t1发现A并没有扭转,因而进行了替换操作,因为在替换操作进行前变量A其实是有变动的,只不过最终又批改回A了,此A非彼A,这时候进行替换操作在一些业务场景下很可能要出问题,要解决ABA问题有2种计划。
阿巴阿巴: 计划一:在对变量进行操作的时候给变量加一个版本号,每次对变量操作都将版本号加1,常见在数据库的乐观锁中可见。
阿巴阿巴: 计划二:Java提供了相应的原子援用类AtomicStampedReference,它通过包装[E,Integer]的元组来对对象标记版本戳stamp,从而防止ABA问题。
阿巴阿巴: 自旋带来的耗费CAS自旋如果很长时间都不胜利,这会给CPU带来很大的开销
阿巴阿巴: 解决方案:1、代码层面毁坏掉for循坏,设置适合的循环次数。2、应用JVM能反对处理器提供的pause指令来晋升效率,它能够提早流水线执行指令,防止耗费过多CPU资源。
阿巴阿巴: CAS只能单变量对于一个共享变量,能够应用CAS形式来保障原子操作,然而当多个共享变量时,那就无奈应用CAS来保障原子性。JDK1.5开始,提供了AtomicReference类来保障援用对象之前的原子性,就能够把多个变量放在一个对象里来进行CAS操作。
阿巴阿巴: 在JDK1.5中新增的java.util.concurrent(JUC),就是建设在CAS之上的,一般来说CAS这种乐观锁适宜读多写少的场景。
面试官见阿巴阿巴对答如流,决定尴尬一下她
面试官: 理解JMM吗,讲一下JMM。
阿巴阿巴: 晓得一些,JMM是JAVA内存模型(JAVA Memory Model),目标是为了屏蔽各种硬件和操作系统之间的内存拜访差别,从而让JAVA程序在各种平台对内存的拜访统一。
阿巴阿巴: 不仅如此,JMM还规定了所有的变量都存储在主存中,每个线程都有本人独立的工作空间,线程对变量的操作必须先从主存中读取到本人的工作内存中而后再进行操作,最初回写回主存。
阿巴阿巴: 对于主存和工作内存的交互JAVA定义了八种操作来实现,且这些操作都是原子性的:lock、unlock、read、load、use、assign、store、write
面试官: 不错不错,那JMM是实在存在的嘛,和JVM内存模型(JAVA 虚拟机内存模型)是一样的嘛?
阿巴阿巴: 不是实在存在的,JMM讲的也只是一种模型,实在的实现可能还是和模型会有差别的。JMM和JVM是不一样的,它们并不是同一个档次的划分,基本上没啥关系。
堆和办法区是线程共享的,虚拟机栈、本地办法栈、程序计数器是线程公有的
程序计数器是这几块区域惟一一个不会产生OOM的区域
面试官: 了解的还不错嘛,那你讲讲Volatile关键字呗
阿巴阿巴: Volatile能够说是JAVA虚拟机提供的最轻量级的同步机制,当一个变量被定义为volatile后,它将具备俩种个性,第一个是保障此变量对所有线程的可见性,即当一个线程扭转了这个变量的值后,其余线程可能立刻感知的到,尽管具备可见性,然而多线程在并发状况下对volatile润饰的变量进行操作时是会有线程安全性的问题的。这是因为volatile润饰的变量在各个线程工作内存中是不存在一致性的,然而因为每次应用都要进行刷新,导致执行引擎看不到不统一的状况。
阿巴阿巴: Volatile润饰的变量的第二个个性是禁止指令重排序优化,一般的变量仅仅会保障在该办法的执行过程中所有依赖的赋值后果的中央都可能获取到正确的后果。而不能保障赋值的程序和代码中的书写程序统一。例如上面的DCL的单例模式。
public class Instance { private String str = ""; private volatile static Instance ins = null; /** * 构造方法私有化 */ private Instance(){ str = "hi"; } /** * DCL获取单例 * @return */ public static Instance getInstance(){ if (ins == null){ synchronized (Instance.class){ if (ins == null){ ins = new Instance(); } } } return ins; }}
阿巴阿巴: 如果下面ins变量不应用volatile变量进行润饰,那么当线程A在获取了Instance.class锁后,对ins变量进行 ins = new Instance() 初始化时,因为这是很多条指令,jvm可能会乱序执行。这个时候如果线程B在执行if (ins == null)时,失常状况下,如果为true,阐明须要获取Instance.class锁,期待初始化。然而这时候,假如线程A再没有对ins进行初始化完,比方只调配了空间,对象还没结构完,然而曾经将援用返回了,这样线程B失去的就是一个未能实例化齐全的对象,从而产生异样。而加了volatile关键字后,如果实例还未初始化实现,那么它的援用是不会向外公布的,这样即可防止异样的产生。
面试官: 不错,你这块都把握的挺扎实的,今天能够来下班了。
阿巴阿巴: 好的
/ 感激反对 /
以上便是本次分享的全部内容,心愿对你有所帮忙^_^
喜爱的话别忘了 分享、点赞、珍藏 三连哦~
欢送关注公众号 程序员巴士,来自字节、虾皮、招银的三端兄弟,分享编程教训、技术干货与职业规划,助你少走弯路进大厂。