17.【参考】volatile 解决多线程内存不可见问题对于一写多读,是可以解决变量同步问题,但是如果多,写,同样无法解决线程安全问题。,说明:如果是 count++操作,使用如下类实现:,AtomicInteger count = new AtomicInteger();,count.addAndGet(1);,如果是 JDK8,推荐使用 LongAdder 对象,比 AtomicLong 性能更好(减少乐观锁的重试次数),上述案例使用的AtomicInteger进行的类似累加的操作,底层使用的volatile来实现的,已经保障了可见性,所以数据一定是正确的。,之所以是CountDownLatch 是为了保障main线程输出结果的时候,所有的线程都已经完成了计算。,解决并发修改多个属性,AtomicInteger、AtomicBoolean等java.util.concurrent包下面的类,但是这个只能并发修改一个属性,如果我需要对多个属性同时进行并发修改,并且保证原子性呢?,AtomicReference和AtomicInteger非常类似,不同之处就在于AtomicInteger是对整数的封装,而AtomicReference则对应普通的对象引用,是操控多个属性的原子性的并发类。,携带版本号的引用类型原子类,可以解决ABA问题,原子更新带有标记位的引用类型对象,它的定义就是将状态戳简化为true|false,,可以理解为上面AtomicStampedReference的简化版,就是不关心修改过几次,仅仅关心是否修改过。因此变量mark是boolean类型,仅记录值是否有过修改。不建议使用。,使用目的:以一种线程安全的方式操作非线程安全对象内的某些字段。,,结果,,官方api,这个类是通常优选AtomicLong当多个线程更新时使用,用于诸如收集统计信息,不用于细粒度同步控制的共同总和。 在低更新争议下,这两类具有相似的特征。 但是,在高度争议的情况下,这一类的预期吞吐量明显高于牺牲更高的空间消耗。,,LongAdder是Striped64的子类,Striped64有几个比较重要的成员函数,cell 是java.util.concurrent.atomic 下 Striped64 的一个内部类,,LongAdder在无竞争的情况,跟AtomicLong一样,对同一个base进行操作。,当出现竞争关系时则采用化整为零的做法,用空间换时间,用一个数组cells将一个value拆分进这个数组cells。多个线程需要同时对value进行操作时候,,对线程id进行hash,再根据hash值映射到这个数组cells的某个下标,再对该下标所对应的值进行自增操作。当所有线程操作完毕,将数组cells的所有值和无竞争值base都加起来作为最终结果。,sum( )会将所有cell数组中的value和base累加作为返回值,核心的思想就是将之前AtomicLong一个value的更新压力分散到多个value中去,从而降级更新热点。,
© 版权声明
文章版权归作者所有,未经允许请勿转载。