1. CAS背后没有加锁,不需要加锁,背后需要靠cpu原语来实现
  2. 已学:synchronized、volatile、Atomic、CAS
  3. 继续学Atomic
  4. 无锁操作效率更高
  5. 多线程对一个数递增的解决方案(经常遇到)
    1. 普通变量加锁
    2. AtomicInt类
    3. LongAdder类(LongAccumulator类)
  6. 上述三种方式的效率高低
    1. synchronized一般比Atomic高,但也有差不多的时候
    2. 粗糙的测试方式(算间隔时间)
    3. JMS测试===>专业、科学
    4. LongAdder(分段锁) > 一般Atomic(无锁) > synchronized(锁升级、锁膨胀 无锁->偏向锁->自旋锁->重量级锁)(将线程数调小或循环数少了LongAdder未必有优势)
  7. 实际中用哪种要考虑一下将来的并发度有多高(线程的并发度会影响这些方法的效率)
  8. 最好进行压测,或者性能测试
  9. 并发度影响性能的原因:
    1. CAS与synchronized选择时:线程数多、执行时间长选synchronized;线程数少、执行时间短选CAS
    2. LongAdder比Atomic快的原因:LongAdder底层是用的分段锁

LongAdder实现原理

  1. 分段锁
  2. 线程数少的时候LongAdder没有什么优势,并发度高的时候LongAdder的优势就出来了
  3. LongAdder使用一个数组,将值放到数组中,刚开始都是0;一共有1000个线程,将250个线程一组锁起来,每一个都往上递增,最后算出结果之后,将结果加起来,加起来的总的就得到了最终的和

image.png

  1. 分段锁也是CAS操作(有可能会问)===>为什么用CAS,因为线程数少并且CAS执行效率相对较高

LongAdder 是 LongAccumulator 的一种特殊形式

  1. LongAdder | LongAccumulator简介
  2. LongAccumulator用得更少!

🤏随想

  1. java object layout===>jol(现实java对象在内存中的结构:markword、class pointer、instance data、对齐填充位)
  2. jvm自增陷阱,count = count++:
    1. 首先执行count=count (count=0)JVM会把count放到临时变量区
    2. 再执行count++
    3. 当++执行完了之后,jvm就会把在临时变量区的count放回来,但是这个时候count还是0
  3. 注:inc指令是直接发生在局部变量表中的,而不是在栈中