• Java-原子操作类


    学习《Java并发编程之美》第4章后,简要记录一下几个原子操作类的语法和原理。

    各种原子操作类内部通过Unsafe使用CAS实现,保证多线程变量的安全性,相比使用锁实现原子性操作,在性能上有很大提高。常用类有AtomicLong、AtomicInteger、AtomicBoolean等

    一、AtomicLong

    1.初始化

    public AtomicLong(long initialValue);若不设值,默认为0

    2.自增自减

    先增减后返回:incrementAndGet()和decrementAndGet()

    先返回值后增减:getAndIncrement()和getAndDecrement()

    3.增量超过1的,减法将参数变为负数即可

    public final long addAndGet(long delta)

    public final long getAndAdd(long delta)

    4.乘除

    atomicLong.set(atomicLong.get()*6);

    看起来不像是原子操作,调用get()前的一瞬间被改动的话,会覆盖掉其他线程的数值

    5.其他的几个类例如AtomicInteger、AtomicBoolean使用方法都差不多

    二、LongAdder

    AtomicLong通过CAS提供的非阻塞的原子性操作,但是大量线程去争抢更新同一个原子变量,只有一个线程成功,其他线程会无限循环不断进行自旋尝试,浪费CPU资源。

    JDK8新增的原子性递增或者递减类LongAdder类就是处理这个问题的,将一个原子变量分解成多个变量,线程获取其中一个即可增减,减少争夺共享资源的并发量。

    1.LongAdder的结构

    Cell数组就是分解后的多个变量,供线程操作;

    base相当于原来的原子变量,初始为0,由Cell数组累加而成;

    cellsBusy用来实现自旋锁,状态值为0或1;

    2.当前线程会访问数组哪个变量?

    源码中有as[getProbe() & m]获取下标,m=数组长度-1,getProbe()用于获取当前线程中变量threadLocalRandomProbe的值,这个值叫探针变量,不同线程不同;

    3.如何初始化Cell数组?

    并发量较少时,Cell数组没有初始化,只调用casBase函数对base变量进行CAS累加;

    并发量逐渐增多时,casBase函数会失败,如果Cell数组为null或者为空,调用longAccumlate函数进行初始化;

    4.如何保证被分配到的Cell元素的原子性?

    用@sun.misc.Contended注解修饰变量避免伪共享

    (1)什么是伪共享?

    高速缓冲存储器是为了解决主内存和CPU运行速度差的问题而存在的中介桥梁,一般被继承道CPU内部,也叫CPU Cache。内部按行存储,行是Cache与主内存进行数据交换的单位,大小为2的幂次方字节。

    同一行有多个变量的话,线程会先找缓存再找主内存。例如缓存行存有x和y两个变量,线程A和B分别从主内存拿到x和y到自己的缓存区,A对x做出修改,y没变。B只需要y但是因为x被改动了,B要重新去主存读取数据。对主存造成压力。

    (2)如何避免伪共享?

    一个缓存行只存一个变量,行内其他字节用其他变量填充;或者用@sun.misc.Contended注解修饰变量,自动填充;

    5.常用方法

    (1)long sum(); 计算LongAdder对象的值,base+Cell数组总和。计算过程没有对Cell数组加锁,期间可能有其他线程进行修改或者扩容,求和结果不精准;

    (2)void reset(); base和Cell数组全部置为0;

    (3)sumThenReset(); sum()+reset(),求和过程中置空;

    (4)add(long x); 加一个值x,想要减值则将x设置为负数; 

  • 相关阅读:
    线性回归(linear regression)之监督学习
    hadoop学习笔记之倒排索引
    Java学习笔记之==与equals
    Java学习笔记之深入理解引用
    mysql
    mysql
    JAVA
    nio
    JVM
    java
  • 原文地址:https://www.cnblogs.com/shoulinniao/p/14882555.html
Copyright © 2020-2023  润新知