LongAdder和AtomicLong

LongAdder

AmoticLong

AtomicLong是作用是对长整形进行原子操作

原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束

在32位操作系统中,64位的long 和 double 变量由于会被JVM当作两个分离的32位来进行操作,所以不具有原子性。而使用AtomicLong能让long的操作保持原子型。

构造方法 
AtomicLong() 
创建一个新的AtomicLong,初始值为 0AtomicLong(long initialValue) 
用给定的初始值创建一个新的AtomicLong。  

long accumulateAndGet(long x, LongBinaryOperator accumulatorFunction) 
使用将给定函数应用于当前值和给定值的结果原子更新当前值,返回更新后的值。  
long addAndGet(long delta) 
将给定的值原子地添加到当前值。  
boolean compareAndSet(long expect, long update) 
如果当前值为 == ,则将原值设置为给定的更新值。  
long decrementAndGet() 
原子减1当前值。  
double doubleValue() 
返回此值 AtomicLong为 double一个宽元转换后。  
float floatValue() 
返回此值 AtomicLong为 float一个宽元转换后。  
long get() 
获取当前值。  
long getAndAccumulate(long x, LongBinaryOperator accumulatorFunction) 
使用给定函数应用给当前值和给定值的结果原子更新当前值,返回上一个值。  
long getAndAdd(long delta) 
将给定的值原子地添加到当前值。  
long getAndDecrement() 
原子减1当前值。  
long getAndIncrement() 
原子上增加一个当前值。  
long getAndSet(long newValue) 
将原子设置为给定值并返回旧值。  
long getAndUpdate(LongUnaryOperator updateFunction) 
用应用给定函数的结果原子更新当前值,返回上一个值。  
long incrementAndGet() 
原子上增加一个当前值。  
int intValue() 
返回此的值 AtomicLong作为 int的基本收缩转换之后。  
void lazySet(long newValue) 
最终设定为给定值。  
long longValue() 
将 AtomicLong的值作为 longvoid set(long newValue) 
设置为给定值。  
String toString() 
返回当前值的String表示形式。  
long updateAndGet(LongUnaryOperator updateFunction) 
使用给定函数的结果原子更新当前值,返回更新的值。  
boolean weakCompareAndSet(long expect, long update) 
如果当前值为 == ,则将原值设置为给定的更新值。  

1.计数功能:(实现在并发环境下是不安全的 结果与期望值不一致)

    private static int count =0;

    public static void main(String[] args) throws Exception {
        List<Thread> tList =  new ArrayList<>();
        for (int i = 0; i <1000; i++) {
            new Thread(()->{ count++;}).start();
        }
		Thread.sleep(1000);//确保线程都结束
        System.out.println(count);
        /*
            result:996
         */
    }

volatile

2.加volatile(结论: volatile关键字并不能作为线程计数器

    private static volatile int count =0;
    public static void main(String[] args) throws Exception {
        List<Thread> tList =  new ArrayList<>();
        for (int i = 0; i <1000; i++) {
            new Thread(()->{ count++;}).start();
        }
		Thread.sleep(1000);//确保线程都结束
        System.out.println(count);
        /*
            result:991
         */
    }

原因:在 java 垃圾回收整理一文中,描述了jvm运行时刻内存的分配。其中有一个内存区域是jvm虚拟机栈,每一个线程运行时都有一个线程栈,

线程栈保存了线程运行时候变量值信息。当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存

变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,

在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。下面一幅图

描述这写交互

java volatile1

read and load 从主存复制变量到当前工作内存
use and assign 执行代码,改变共享变量值
store and write 用工作内存数据刷新主存相关内容

其中use and assign 可以多次出现

但是这一些操作并不是原子性,也就是 在read load之后,如果主内存count变量发生修改之后,线程工作内存中的值由于已经加载,不会产生对应的变化,所以计算出来的结果会和预期不一样

对于volatile修饰的变量,jvm虚拟机只是保证从主内存加载到线程工作内存的值是最新的

例如假如线程1,线程2 在进行read,load 操作中,发现主内存中count的值都是5,那么都会加载这个最新的值

在线程1堆count进行修改之后,会write到主内存中,主内存中的count变量就会变为6

线程2由于已经进行read,load操作,在进行运算之后,也会更新主内存count的变量值为6

导致两个线程及时用volatile关键字修改之后,还是会存在并发的情况。

转载于:https://www.cnblogs.com/jianwei-dai/p/6246067.html

synchronized

  1. 使用synchronized(结果正确)

        private static int count =0;
        public static void main(String[] args) throws Exception {
            List<Thread> tList =  new ArrayList<>();
            for (int i = 0; i <1000; i++) {
                new Thread(()->{
                    synchronized (ThreadTest1.class){
                        count++;
                    }
                }).start();
            }
            Thread.sleep(1000);//确保线程都结束
            System.out.println(count);
            /*
                result:1000
             */
        }
    

    问题:Synchronized悲观锁,是独占的,意味着如果有别的线程在执行,当前线程只能是等待!

    JDK1.5以后这种轻量级的解决方案不再推荐使用synchronized,而使用Atomic代替,因为效率更高

    AotmicInteger其实就是对int的包装,然后里面内部使用CAS算法来保证操作的原子性

    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }
    可以看到,内部主要依赖于unsafe提供的CAS算法来实现的
    

AmoticLong

  1. 用AmoticLong

        private static AtomicLong count = new AtomicLong(0);
        public static void main(String[] args) throws Exception {
            List<Thread> tList =  new ArrayList<>();
            for (int i = 0; i <1000; i++) {
                new Thread(()->{
                    count.incrementAndGet();
                }).start();
            }
            Thread.sleep(1000);//确保线程都结束
            System.out.println(count.get());
            /*
                result:1000
             */
        }
    

    问题:

    AtomicLong的实现方式是CAS.

    CAS机制就是,在一个死循环内,不断尝试修改目标值,直到修改成功。如果竞争不激烈,那么修改成功的概率就很高,否则,修改失败的的概率就很高,在大量修改失败时,这些原子操作就会进行多次循环尝试,因此性能就会受到影响

longAdder

将AtomicInteger的内部核心数据value分离成一个数组,每个线程访问时,通过哈希等算法映射到其中一个数字进行计数,而最终的计数结果,则为这个数组的求和累加。热点数据value被分离成多个单元cell,每个cell独自维护内部的值,当前对象的实际值由所有的cell累计合成,这样热点就进行了有效的分离,提高了并行度。

    static LongAdder count = new LongAdder();
    public static void main(String[] args) throws Exception {
        List<Thread> tList =  new ArrayList<>();
        for (int i = 0; i <1000; i++) {
            new Thread(()->{
                count.add(1);
            }).start();
        }
        Thread.sleep(1000);//确保线程都结束
        System.out.println(count.longValue());
        /*
            result:1000
         */
    }

LongAdder和AmoticLong性能测试

public static void main(String[] args) throws Exception {
        test(1);
        test(10);
        test(20);
        test(40);
        test(100);
    }

    static  void test(int threadCount) throws Exception{
        System.out.print("threadCount:" + threadCount+"    ");
        Long startTime = System.currentTimeMillis();
        testLongAdder(threadCount) ;
        System.out.print("LongAdder run time :" + (System.currentTimeMillis() - startTime)+"       ");
        Long startTime2 = System.currentTimeMillis();
        testAmoticLong(threadCount) ;
        System.out.println("AmoticLong run time :" + (System.currentTimeMillis() - startTime2));

        /*
            threadCount:1    LongAdder run time :131       AmoticLong run time :55
            threadCount:10    LongAdder run time :192       AmoticLong run time :2060
            threadCount:20    LongAdder run time :332       AmoticLong run time :4081
            threadCount:40    LongAdder run time :779       AmoticLong run time :6876
            threadCount:100    LongAdder run time :1627       AmoticLong run time :20495
         */

    }

    static LongAdder count = null;
    static void testLongAdder(int threadCount) throws Exception{
        count = new LongAdder();
        List<Thread> list = new ArrayList<>();
        for (int i = 0; i <threadCount; i++) {
            Thread t= new Thread(()->{
                for (int j = 0; j < 10000000; j++) {
                    count.add(1);
                }
            });
            list.add(t);
        }
        for(Thread t:list){t.start();}
        for(Thread t:list){t.join();}
    }


    private static AtomicLong countAmotic = null;
    static void testAmoticLong(int threadCount) throws Exception{
        countAmotic =  new AtomicLong(0);
        List<Thread> list = new ArrayList<>();
        for (int i = 0; i <threadCount; i++) {
            Thread t= new Thread(()->{
                for (int j = 0; j < 10000000; j++) {
                    countAmotic.incrementAndGet();
                }
            });
            list.add(t);
        }
        for(Thread t:list){t.start();}
        for(Thread t:list){t.join();}
    }

结论:AtomicLong在线程数量低的时候 性能和LongAdder相近,优于LongAdder,但是线程数量多了 性能明显低于LongAdder,

            countAmotic.incrementAndGet();
            }
        });
        list.add(t);
    }
    for(Thread t:list){t.start();}
    for(Thread t:list){t.join();}
}

结论:AtomicLong在线程数量低的时候 性能和LongAdder相近,优于LongAdder,但是线程数量多了 性能明显低于LongAdder,

​	所以 **用LongAdder替代AtomicLong**
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值