Java核心技术面试精讲
杨晓峰
前Oracle首席工程师
立即订阅
43250 人已学习
课程目录
已完结 43 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 以面试题为切入点,有效提升你的Java内功
免费
模块一 Java基础 (14讲)
第1讲 | 谈谈你对Java平台的理解?
第2讲 | Exception和Error有什么区别?
第3讲 | 谈谈final、finally、 finalize有什么不同?
第4讲 | 强引用、软引用、弱引用、幻象引用有什么区别?
第5讲 | String、StringBuffer、StringBuilder有什么区别?
第6讲 | 动态代理是基于什么原理?
第7讲 | int和Integer有什么区别?
第8讲 | 对比Vector、ArrayList、LinkedList有何区别?
第9讲 | 对比Hashtable、HashMap、TreeMap有什么不同?
第10讲 | 如何保证集合是线程安全的? ConcurrentHashMap如何实现高效地线程安全?
第11讲 | Java提供了哪些IO方式? NIO如何实现多路复用?
第12讲 | Java有几种文件拷贝方式?哪一种最高效?
第13讲 | 谈谈接口和抽象类有什么区别?
第14讲 | 谈谈你知道的设计模式?
模块二 Java进阶 (16讲)
第15讲 | synchronized和ReentrantLock有什么区别呢?
第16讲 | synchronized底层如何实现?什么是锁的升级、降级?
第17讲 | 一个线程两次调用start()方法会出现什么情况?
第18讲 | 什么情况下Java程序会产生死锁?如何定位、修复?
第19讲 | Java并发包提供了哪些并发工具类?
第20讲 | 并发包中的ConcurrentLinkedQueue和LinkedBlockingQueue有什么区别?
第21讲 | Java并发类库提供的线程池有哪几种? 分别有什么特点?
第22讲 | AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?
第23讲 | 请介绍类加载过程,什么是双亲委派模型?
第24讲 | 有哪些方法可以在运行时动态生成一个Java类?
第25讲 | 谈谈JVM内存区域的划分,哪些区域可能发生OutOfMemoryError?
第26讲 | 如何监控和诊断JVM堆内和堆外内存使用?
第27讲 | Java常见的垃圾收集器有哪些?
第28讲 | 谈谈你的GC调优思路?
第29讲 | Java内存模型中的happen-before是什么?
第30讲 | Java程序运行在Docker等容器环境有哪些新问题?
模块三 Java安全基础 (2讲)
第31讲 | 你了解Java应用开发中的注入攻击吗?
第32讲 | 如何写出安全的Java代码?
模块四 Java性能基础 (3讲)
第33讲 | 后台服务出现明显“变慢”,谈谈你的诊断思路?
第34讲 | 有人说“Lambda能让Java程序慢30倍”,你怎么看?
第35讲 | JVM优化Java代码时都做了什么?
模块5 Java应用开发扩展 (4讲)
第36讲 | 谈谈MySQL支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景?
第37讲 | 谈谈Spring Bean的生命周期和作用域?
第38讲 | 对比Java标准NIO类库,你知道Netty是如何实现更高性能的吗?
第39讲 | 谈谈常用的分布式ID的设计方案?Snowflake是否受冬令时切换影响?
周末福利 (2讲)
周末福利 | 谈谈我对Java学习和面试的看法
周末福利 | 一份Java工程师必读书单
结束语 (1讲)
结束语 | 技术没有终点
Java核心技术面试精讲
登录|注册

第22讲 | AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?

杨晓峰 2018-06-26
在今天这一讲中,我来分析一下并发包内部的组成,一起来看看各种同步结构、线程池等,是基于什么原理来设计和实现的。
今天我要问你的问题是,AtomicInteger 底层实现原理是什么?如何在自己的产品代码中应用 CAS 操作?

典型回答

AtomicIntger 是对 int 类型的一个封装,提供原子性的访问和更新操作,其原子性操作的实现是基于 CAS(compare-and-swap)技术。
所谓 CAS,表征的是一些列操作的集合,获取当前数值,进行一些运算,利用 CAS 指令试图进行更新。如果当前数值未变,代表没有其他线程进行并发修改,则成功更新。否则,可能出现不同的选择,要么进行重试,要么就返回一个成功或者失败的结果。
从 AtomicInteger 的内部属性可以看出,它依赖于 Unsafe 提供的一些底层能力,进行底层操作;以 volatile 的 value 字段,记录数值,以保证可见性。
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long VALUE = U.objectFieldOffset(AtomicInteger.class, "value");
private volatile int value;
具体的原子操作细节,可以参考任意一个原子更新方法,比如下面的 getAndIncrement。
Unsafe 会利用 value 字段的内存地址偏移,直接完成操作。
public final int getAndIncrement() {
return U.getAndAddInt(this, VALUE, 1);
}
因为 getAndIncrement 需要返归数值,所以需要添加失败重试逻辑。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Java核心技术面试精讲》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(24)

  • wenxueliu
    建议;

    1. 希望能有推外内存的主题,范型部分希望能与cpp比较讲解。
    2. 一些主题如果已经有公开的比较好的资料,可以提供链接,对重点强调即可。希望能看到更多公开资料所没有的信息,这也是老鸟们付费的初衷。
    同意的点赞
    2018-06-26
    1
    95
  • 墨飞域
    这一讲对于我来说,挺有难度的,还是基础比较薄弱,整体上没太听懂。老师对于Java的理解真是太深入了,等我以后技术精进了,再回来看看老师的36讲,应该会有新的认识。继续往下听吧,已经懂点的加深理解,没听过的就当是听了名字以后用到了再仔细研究
    2018-08-07
    21
  • OneThin
    能否出一节讲一下unsafe,感觉这个才是最基础的。另外unsafe为什么叫unsafe呢
    2018-07-16
    12
  • Cui
    老师,看了AQS的实现原理后,我再回顾了您之前关于synchronized的文章,心中有些疑问:
    1、synchronized在JVM中是会进行锁升级和降级的,并且是基于CAS来掌握竞争的情况,在竞争不多的情况下利用CAS的轻量级操作来减少开销。
    2、而AQS也是基于CAS操作队列的,位于队列头的节点优先获得锁,其他的节点会被LockSupport.park()起来(这个好像依赖的是操作系统的互斥锁,应该也是个重量级操作)。
    我觉得这两种方式都是基于CAS操作的,只是操作的对象不同(一个是Mark Word,一个是队列节点),当竞争较多时,还是不可避免地会使用到操作系统的互斥锁。然而,我再测试这两者的性能时,在无竞争的情况下,两者性能相当,但是,当竞争起来后,AQS的性能明显比synchronized要好(测试案例是8个线程并发对一个int递增,每个线程递增1000万次,AQS的耗时大概要少30%),这是为什么呢?

    作者回复: Locksupport的实现据说速度快,我也没具体对比过;不过jdk9里,monitor相关操作也加快了,可以看看jep143

    2018-06-26
    11
  • 三口先生
    大于0取消状态,小于0有效状态,表示等待状态四种cancelled,signal,condition,propagate

    作者回复: 不错

    2018-06-26
    11
  • I.am DZX
    CANCELLED 1 因为超时或中断设置为此状态,标志节点不可用
    SIGNAL -1 处于此状态的节点释放资源时会唤醒后面的节点
    CONDITION -2 处于条件队列里,等待条件成立(signal signalall) 条件成立后会置入获取资源的队列里
    PROPAGATE -3 共享模式下使用,头节点获取资源时将后面节点设置为此状态,如果头节点获取资源后还有足够的资源,则后面节点会尝试获取,这个状态主要是为了共享状态下队列里足够多的节点同时获取资源
    0 初始状态

    作者回复: 好

    2018-06-26
    9
  • 二木🐶
    一直很好奇,为何CAS指令在发现内容未变的时候就能判断没有其他线程修改呢?可能被修改后的值与比较的值一样呀
    2018-06-28
    6
  • 卡斯瓦德
    老师请教个问题,acquireQueued的源代码中,使用for(;;)做了个自旋锁吧,作者为什么不用while(true),这种方式呢,是因为开销不一样吗?

    作者回复: 也许,这个我不知道具体原因,看上去while会比for多一个变量

    2018-07-05
    4
  • 黄明恩
    老师可否分析下Object.wait和notify的原理
    2018-06-28
    2
  • 三木子
    最近遇到配置tomcat连接池,导致cpu过高问题,最后发现配置连接池数过大导致上下文切换次数过多
    ,也就是线程池中任务数过少,空闲的线程过多,我想问为什么会导致上下文切换过多?
    2018-06-26
    2
  • 77爸比
    CAS有部分实现是解决ABA问题,可以讲一下ABA问题是如何解决的,除了version外,还有没有其他的方式
    2018-07-09
    1
  • Paul Shan
    CAS适用的场景是多数修改都成功,少数不成功的修改靠增加CPU来轮询,也就是说只有CPU轮询付出的代价足够小才经济。
    2019-11-26
  • prepared
    行尾注释不建议吧
    2019-11-20
  • 亮灯
    老师,您好, shouldParkAfterFailedAcquire表示是否挂起当前线程,为什么要有这个判断?这个判断有什么用?
    2019-10-15
  • 流光
    老师,您的倒数第二个方法是非公平说的获取方法没问题,最后的acquireQueued()是公平锁的获取方法,前天面试就被面试官喷了
    2019-07-03
    1
  • Pine
    请教老师一个问题,基本类型前面加volatile,大概能明白什么意思。 可加在引用类型前面就不是很明白了?
    2019-04-30
  • 星辰
    关于状态的其他童鞋已经说啦,

    AQS的Node中包含了 Thread和waitStatus,也就是链表中需要获取锁的线程吧~!
    2019-04-28
  • Geek_987169
    老师,您说的"更加紧凑",是什么意思?不太理解
    2019-03-26
  • ylw666
    LongAdder这里,说要考虑紧凑性的影响,不清楚指的是哪方面的考虑

    作者回复: 紧凑就是说内存使用效率,有些高性能应用会对此提出苛刻要求

    2019-01-26
  • 约书亚
    全局最看不懂的cancelAcquire方法没说...
    2018-11-16
收起评论
24
返回
顶部