LongAdder的理解

LongAdder

LongAdder继承自Striped64,Striped64有一个内部类Cell以及该类的数组,
还又有一个字段叫base,base就是初始值.

Cell

Cell内部有一个字段value,该字段是对base值的增加值,就是当多个线程访问
LongAdder时,会给该线程分配一个Cell,分配方式为
cells[ThreadLocalRandom.current()%cells.length],
然后让该线程的修改用cas操作放在该Cell的中value中,cells的初始长度为2,最
大长度为cpu的核心数.
ThreadLocalRandom.current()是每个线程单独的Random,Random不是线程安全,
该方法会产生一个随机数.
一个cell是会被多个线程访问的,ThreadLocalRandom.current()%cells.length的结果
很可能是相同的,运气不好的话,所有的结果都相等,这个时候LongAdder和AtomicLong
的效率就差不多了.
当然了,该Cell类还加上了@sun.misc.Contended注解,表示每个Cell单独占用
一个缓存行,避免虚共享.

虚共享

虚共享的产生:目前cpu都有三级缓存l1,l2,l3,缓存中的数据存放是一行一行的,
一行是64个字节,long变量的大小是64位也就是8个字节,需要8个long变量才能
填满一个缓存行.
当对一个volatile变量进行操作时,由于缓存一致性协议,要让所
有的线程都对这个变量的修改可见,所有的线程就要将该变量所在的缓存行清空,
结果就导致本来对一个变量的操作,影响了该缓存行存在的其他变量,导致其他变量
也要去内存重新读取,造成不必要的时间开销.
想要避免这个开销,就要拿空间换时间了,一个long是8字节,再填充7个long就行了,
就像这样:
	long value;
	long p0, p1, p2, p3, p4, p5, p6;
@sun.misc.Contended加上后就相当于这样做了,这样做之后虽然造成了空间的浪
费,但是省去了时间,当然啦,cpu的缓存可是很小的,一个缓存行也是很珍贵的,这就
需要我们自己去衡量了.

基本原理

当只有一个线程访问LongAdder时直接返回base
当只有一个线程修改LongAdder时直接对base进行cas操作
当有多个线程访问LongAdder时返回base + cells的所有value值
当有多个线程修改时LongAdder时,每个线程只对自己对应的cell进行cas操作,
避免了不必要的竞争.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值