重庆网领网站建设公司,网站开发需要经费么,wordpress 5,3小说网站开发文章目录 一、Java原子操作类概述1、什么是原子操作类2、为什么要用原子操作类3、CAS入门 二、基本类型原子类1、概述2、代码实例 三、数组类型原子类1、概述2、代码实例 四、引用类型原子类1、概述2、AtomicReference3、ABA问题与AtomicStampedReference4、一次性修改#xf… 文章目录 一、Java原子操作类概述1、什么是原子操作类2、为什么要用原子操作类3、CAS入门 二、基本类型原子类1、概述2、代码实例 三、数组类型原子类1、概述2、代码实例 四、引用类型原子类1、概述2、AtomicReference3、ABA问题与AtomicStampedReference4、一次性修改AtomicMarkableReference 五、对象属性修改原子类1、概述2、使用要求3、为什么要用对象属性修改原子类4、AtomicIntegerFieldUpdater使用实例5、AtomicReferenceFieldUpdater使用实例5、AtomicIntegerFieldUpdater与synchronized、AtomicInteger效率对比 六、原子操作增强类1、概述2、LongAdder常用方法3、LongAdder使用实例4、LongAccumulator5、synchronized、AtomicLong、LongAdder、LongAccumulator性能对比 七、LongAdder源码分析 一、Java原子操作类概述
1、什么是原子操作类
Java从JDK1.5开始提供了java.util.concurrent.atomic包这个包中的原子操作类提供了一种用法简单性能高效线程安全地更新一个变量的方式。
2、为什么要用原子操作类
《阿里巴巴Java开发手册中》
【参考】 volatile 解决多线程内存不可见问题。对于一写多读是可以解决变量同步问题但是如果多写同样无法解决线程安全问题。 说明 如果是 count操作使用如下类实现 AtomicInteger count new AtomicInteger(); count.addAndGet(1); 如果是 JDK8推荐使用 LongAdder 对象比 AtomicLong 性能更好减少乐观锁的重试次数。
在 Java 语言中我们可以通过 synchronized 关键字或者锁Lock来实现部分的原子性控制。然而这种方式可能会造成性能上的问题特别是在高并发的情况下。因此Java 提供了一系列的原子类如 AtomicIntegerAtomicLong 等这些类使用了硬件级别的原子操作指令能够在无锁的情况下实现高效的原子操作。
3、CAS入门
我知道乐观锁但是我的确不知道CAS啊到底什么是CAS
总的来说原子操作类是基于CAS实现的这些类在内部使用了非阻塞算法和硬件级别的 CAS 操作Compare and Swap比较并交换保证了并发环境下的原子性和高性能。
二、基本类型原子类
1、概述
基本类型原子类包括AtomicBoolean、AtomicInteger、AtomicLong
主要有以下几个常用方法
// 自动更新当前值与给定的功能应用到当前和给定值的结果返回更新后的值。
int accumulateAndGet(int x, IntBinaryOperator accumulatorFunction) // 自动添加给定值并获取当前值。
int addAndGet(int delta) // 自动设置的值来指定更新值如果给定期望值。
boolean compareAndSet(int expect, int update) // 递减
int decrementAndGet() // 为扩大基本转换后的 double返回该 AtomicInteger值。
double doubleValue() // 为扩大基本转换后的 float返回该 AtomicInteger值。
float floatValue() // 获取当前值。
int get() // 自动更新当前值与给定的功能应用到当前和给定值的结果返回前一个值。
int getAndAccumulate(int x, IntBinaryOperator accumulatorFunction) // 自动添加给定值并获取当前值。
int getAndAdd(int delta) // 获取并递减
int getAndDecrement() // 获取并递增
int getAndIncrement() // 获取值并设置新值
int getAndSet(int newValue) // 通过函数式接口更新值
int getAndUpdate(IntUnaryOperator updateFunction) // 递增并且获取
int incrementAndGet() // 作为一个 int返回该 AtomicInteger值。
int intValue() // 最终设置为给定的值。
void lazySet(int newValue) // 为扩大基本转换后的 long返回该 AtomicInteger值。
long longValue() // 设置值
void set(int newValue) // 返回当前值的字符串表示形式。
String toString() // 自动更新当前值与结果应用给定的函数返回更新后的值。
int updateAndGet(IntUnaryOperator updateFunction) // 自动设置的值来指定更新值如果修改值期望值。
boolean weakCompareAndSet(int expect, int update)
2、代码实例
使用原子操作类可以保证所有的操作都是原子操作高并发下可以保证线程安全。
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;class MyNumber
{AtomicInteger atomicInteger new AtomicInteger();public void addPlusPlus(){atomicInteger.getAndIncrement();}
}public class AtomicIntegerDemo
{public static final int SIZE 50;public static void main(String[] args) throws InterruptedException{MyNumber myNumber new MyNumber();CountDownLatch countDownLatch new CountDownLatch(SIZE);for (int i 1; i SIZE; i) {new Thread(() - {try {for (int j 1; j 1000; j) {myNumber.addPlusPlus();}} finally {countDownLatch.countDown();}},String.valueOf(i)).start();}//等待上面50个线程全部计算完成后再去获得最终值countDownLatch.await();System.out.println(Thread.currentThread().getName()\tresult: myNumber.atomicInteger.get());}
}三、数组类型原子类
1、概述
数组类型原子类顾名思义是基本类型与引用类型原子类的数组包括AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray引用类型的数组。
主要常用方法
// 使用将给定函数 更新i下标处的值为x 并返回更新后的值
int accumulateAndGet(int i, int x, IntBinaryOperator accumulatorFunction) // 下标i 的值加delta
int addAndGet(int i, int delta) // 下标i 的值如果等于期望值就设置为update返回是否更新成功
boolean compareAndSet(int i, int expect, int update) // 下标i 递减并返回
int decrementAndGet(int i) // 获取下标i 的值
int get(int i) // 获取值并通过给定函数设置下标i 的值
int getAndAccumulate(int i, int x, IntBinaryOperator accumulatorFunction) // 获取下标i的值并加上给定的值
int getAndAdd(int i, int delta) // 获取下标i的值并减1
int getAndDecrement(int i) // 获取下标i的值并加1
int getAndIncrement(int i) // 获取下标i的值并设置为新值
int getAndSet(int i, int newValue)
// 获取下标i的值并通过函数设置新值
int getAndUpdate(int i, IntUnaryOperator updateFunction) // 递增下标i的值并返回递增后的值
int incrementAndGet(int i)
// 懒加载
void lazySet(int i, int newValue)
// 数组长度
int length()
// 设置下标i的值
void set(int i, int newValue) // 通过函数修改值并且获取修改后的值
int updateAndGet(int i, IntUnaryOperator updateFunction) // 修改值
boolean weakCompareAndSet(int i, int expect, int update) 我们可以发现数组类型原子类与基本类型原子类的方法大同小异无非是可以自由的操作数组中某个下标的值。
2、代码实例
public class AtomicIntegerArrayDemo
{public static void main(String[] args){AtomicIntegerArray atomicIntegerArray new AtomicIntegerArray(new int[5]);//AtomicIntegerArray atomicIntegerArray new AtomicIntegerArray(5);//AtomicIntegerArray atomicIntegerArray new AtomicIntegerArray(new int[]{1,2,3,4,5});for (int i 0; i atomicIntegerArray.length(); i) {System.out.println(atomicIntegerArray.get(i));}System.out.println();int tmpInt 0;tmpInt atomicIntegerArray.getAndSet(0,1122);System.out.println(tmpInt\tatomicIntegerArray.get(0));tmpInt atomicIntegerArray.getAndIncrement(0);System.out.println(tmpInt\tatomicIntegerArray.get(0));}
}四、引用类型原子类
1、概述
引用类型原子类就是可以操作自定义类型的原子类包括AtomicReference、AtomicStampedReference、AtomicMarkableReference。
其主要方法基本也都相似此处就不一一举例了。
2、AtomicReference
以下实例中使用AtomicReference实现了对User类型的原子操作
import java.util.concurrent.atomic.AtomicReference;
/**
* 原子引用
* 如果想包装某个类就用原子引用
*/
public class AtomicReferenceDemo {public static void main(String[] args) {User u1 new User(zhangsan, 14);User u2 new User(lisi, 15);AtomicReferenceUser atomicReference new AtomicReference();atomicReference.set(u1);// true 设置为lisiSystem.out.println(atomicReference.compareAndSet(u1, u2) 当前值 atomicReference.get().getName());// false 还是lisiSystem.out.println(atomicReference.compareAndSet(u1, u2) 当前值 atomicReference.get().getName());}
}class User{private String name;private Integer age;public User(String name, Integer age) {this.name name;this.age age;}public String getName() {return name;}public void setName(String name) {this.name name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age age;}
}3、ABA问题与AtomicStampedReference
CAS会导致“ABA问题”。
CAS算法实现一个重要前提需要取出内存中某时刻的数据并在当下时刻比较并替换那么在这个时间差类会导致数据的变化。
比如说一个线程1从内存位置V中取出A这时候另一个线程2也从内存中取出A并且线程2进行了一些操作将值变成了B然后线程2又将值变成A。此时线程1进行CAS操作发现内存中仍然是A然后线程1操作成功。
尽管线程1的CAS操作成功但是不代表这个过程就是没有问题的。
中间过程如果不介意别人动过那无所谓。
中间过程别人不能动那就有问题了。
// ABA问题的产生与解决
public class ABADemo
{static AtomicInteger atomicInteger new AtomicInteger(100);static AtomicStampedReferenceInteger stampedReference new AtomicStampedReference(100,1);public static void main(String[] args){new Thread(() - {int stamp stampedReference.getStamp();System.out.println(Thread.currentThread().getName()\t首次版本号stamp);//暂停500毫秒,保证后面的t4线程初始化拿到的版本号和我一样try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }stampedReference.compareAndSet(100,101,stampedReference.getStamp(),stampedReference.getStamp()1);System.out.println(Thread.currentThread().getName()\t2次流水号stampedReference.getStamp());stampedReference.compareAndSet(101,100,stampedReference.getStamp(),stampedReference.getStamp()1);System.out.println(Thread.currentThread().getName()\t3次流水号stampedReference.getStamp());},t3).start();new Thread(() - {int stamp stampedReference.getStamp();System.out.println(Thread.currentThread().getName()\t首次版本号stamp);//暂停1秒钟线程,等待上面的t3线程发生了ABA问题try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }boolean b stampedReference.compareAndSet(100, 2022, stamp, stamp 1);System.out.println(b\tstampedReference.getReference()\tstampedReference.getStamp());},t4).start();}// ABA问题的产生private static void abaHappen(){new Thread(() - {atomicInteger.compareAndSet(100,101);try { TimeUnit.MILLISECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); }atomicInteger.compareAndSet(101,100);},t1).start();new Thread(() - {try { TimeUnit.MILLISECONDS.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); }System.out.println(atomicInteger.compareAndSet(100, 2022)\tatomicInteger.get());},t2).start();}
}以上实例我们使用AtomicStampedReference对每次操作都使用一个版本号来解决并且每次修改数据将版本号1可以解决ABA问题。
4、一次性修改AtomicMarkableReference
AtomicMarkableReference维护一个对象引用和一个标记位true、false该标记位可以通过原子方式进行更新。
类似于将AtomicStampedReference时间戳状态简化为了true、false常用于对象初始化工作。
isMarked()方法返回当前的标记值true、false 关键方法 compareAndSet(V expectedReference, V newReference, boolean expectedMark, boolean newMark)可以根据预期的标记值和新的标记值、预期的对象和新的对象自由的设置值。
public class AtomicMarkableReferenceDemo
{static AtomicMarkableReference markableReference new AtomicMarkableReference(100,false);public static void main(String[] args){new Thread(() - {boolean marked markableReference.isMarked();System.out.println(Thread.currentThread().getName()\t默认标识marked);//暂停1秒钟线程,等待后面的T2线程和我拿到一样的模式flag标识都是falsetry { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }markableReference.compareAndSet(100,1000,marked,!marked);},t1).start();new Thread(() - {boolean marked markableReference.isMarked();System.out.println(Thread.currentThread().getName()\t默认标识marked);try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }boolean b markableReference.compareAndSet(100, 2000, marked, !marked);System.out.println(Thread.currentThread().getName()\tt2线程CASresult b);System.out.println(Thread.currentThread().getName()\tmarkableReference.isMarked());System.out.println(Thread.currentThread().getName()\tmarkableReference.getReference());},t2).start();}
}五、对象属性修改原子类
1、概述
对象属性修改原子类就是用于直接修改对象的属性以一种线程安全的方式操作非线程安全对象内的某些字段。
包含三个类AtomicIntegerFieldUpdater原子更新对象中int、Integer类型字段的值、AtomicLongFieldUpdater原子更新对象中Long、long类型字段的值、AtomicReferenceFieldUpdater原子更新引用类型字段的值。
2、使用要求
更新的对象属性必须使用volatile修饰符否则会报错 因为对象的属性修改类型原子类都是抽象类所以每次使用都必须使用静态方法newUpdater()创建一个更新器并且需要设置想要更新的类和属性。
3、为什么要用对象属性修改原子类
比如以下实例银行转账想要通过传统方式只能使用synchronized或者Lock保证线程安全而这种方式会使并发量急剧下降又或者使用AtomicInteger原子类保证线程安全但是该字段又无法通过JSON、MyBatis等数据库操作或者其他操作自动转换此时就考虑使用AtomicIntegerFieldUpdater。
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;class BankAccount//资源类
{String bankName CCB;private volatile int money 0;//钱数public void add(){money;}public int getMoney() {return money;}
}/*** 以一种线程安全的方式操作非线程安全对象的某些字段。** 需求* 10个线程* 每个线程转账1000*/
public class AtomicIntegerFieldUpdaterDemo
{public static void main(String[] args) throws InterruptedException{BankAccount bankAccount new BankAccount();CountDownLatch countDownLatch new CountDownLatch(10);for (int i 1; i 10; i) {new Thread(() - {try {for (int j 1; j 1000; j) {bankAccount.add();}} finally {countDownLatch.countDown();}},String.valueOf(i)).start();}countDownLatch.await();System.out.println(Thread.currentThread().getName()\tresult: bankAccount.getMoney());}
}4、AtomicIntegerFieldUpdater使用实例
AtomicIntegerFieldUpdater的方法与上述原子引用类相似此处不再详细解释。
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;class BankAccount//资源类
{String bankName CCB;//更新的对象属性必须使用 volatile 修饰符。private volatile int money 0;//钱数public void add(){money;}public int getMoney() {return money;}//因为对象的属性修改类型原子类都是抽象类所以每次使用都必须// 使用静态方法newUpdater()创建一个更新器并且需要设置想要更新的类和属性。AtomicIntegerFieldUpdaterBankAccount fieldUpdater AtomicIntegerFieldUpdater.newUpdater(BankAccount.class,money);//不加synchronized保证高性能原子性局部微创小手术public void transMoney(BankAccount bankAccount){fieldUpdater.getAndIncrement(bankAccount);}}/*** 以一种线程安全的方式操作非线程安全对象的某些字段。** 需求* 10个线程* 每个线程转账1000* 不使用synchronized,尝试使用AtomicIntegerFieldUpdater来实现。*/
public class AtomicIntegerFieldUpdaterDemo
{public static void main(String[] args) throws InterruptedException{BankAccount bankAccount new BankAccount();CountDownLatch countDownLatch new CountDownLatch(10);for (int i 1; i 10; i) {new Thread(() - {try {for (int j 1; j 1000; j) {//bankAccount.add();bankAccount.transMoney(bankAccount);}} finally {countDownLatch.countDown();}},String.valueOf(i)).start();}countDownLatch.await();System.out.println(Thread.currentThread().getName()\tresult: bankAccount.getMoney());}
}
5、AtomicReferenceFieldUpdater使用实例
AtomicReferenceFieldUpdater与AtomicIntegerFieldUpdater使用类似AtomicReferenceFieldUpdater用于更新更复杂的属性。
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;class MyVar //资源类
{public volatile Boolean isInit Boolean.FALSE;AtomicReferenceFieldUpdaterMyVar,Boolean referenceFieldUpdater AtomicReferenceFieldUpdater.newUpdater(MyVar.class,Boolean.class,isInit);public void init(MyVar myVar){if (referenceFieldUpdater.compareAndSet(myVar,Boolean.FALSE,Boolean.TRUE)){System.out.println(Thread.currentThread().getName()\t----- start init,need 2 seconds);//暂停几秒钟线程try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }System.out.println(Thread.currentThread().getName()\t----- over init);}else{System.out.println(Thread.currentThread().getName()\t----- 已经有线程在进行初始化工作。。。。。);}}
}/*** 需求* 多线程并发调用一个类的初始化方法如果未被初始化过将执行初始化工作* 要求只能被初始化一次只有一个线程操作成功*/
public class AtomicReferenceFieldUpdaterDemo
{public static void main(String[] args){MyVar myVar new MyVar();for (int i 1; i 5; i) {new Thread(() - {myVar.init(myVar);},String.valueOf(i)).start();}}
}
5、AtomicIntegerFieldUpdater与synchronized、AtomicInteger效率对比
我们简单使用一个小例子通过结果我们发现AtomicIntegerFieldUpdater方式性能比AtomicInteger稍差一些但是远优于synchronized
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;public class Test {static class Bank {/*** 使用AtomicIntegerFieldUpdater*/public volatile int fieldUpdaterMoney 0;AtomicIntegerFieldUpdaterTest.Bank fieldUpdater AtomicIntegerFieldUpdater.newUpdater(Test.Bank.class,fieldUpdaterMoney);public void fieldUpdaterMoney(Test.Bank bankAccount){fieldUpdater.getAndIncrement(bankAccount);}/*** 使用synchronized*/public int synchronizedMoney 0;public synchronized void synchronizedMoney(){synchronizedMoney;}/*** 使用AtomicInteger*/AtomicInteger atomicIntegerMoney new AtomicInteger(0);public void atomicIntegerMoney() {atomicIntegerMoney.getAndIncrement();}}public static final int threadNumber 50;public static final int _1W 10000;public static void main(String[] args) throws InterruptedException {long startTime;long endTime;CountDownLatch countDownLatch1 new CountDownLatch(threadNumber);CountDownLatch countDownLatch2 new CountDownLatch(threadNumber);CountDownLatch countDownLatch3 new CountDownLatch(threadNumber);Bank bank new Bank();startTime System.currentTimeMillis();for (int i 1; i threadNumber; i) {new Thread(() - {try {for (int j 1; j 100 * _1W; j) {bank.synchronizedMoney();}} finally {countDownLatch1.countDown();}},String.valueOf(i)).start();}countDownLatch1.await();endTime System.currentTimeMillis();System.out.println(----costTime: (endTime - startTime) 毫秒\t synchronizedMoney: bank.synchronizedMoney);startTime System.currentTimeMillis();for (int i 1; i threadNumber; i) {new Thread(() - {try {for (int j 1; j 100 * _1W; j) {bank.atomicIntegerMoney();}} finally {countDownLatch2.countDown();}},String.valueOf(i)).start();}countDownLatch2.await();endTime System.currentTimeMillis();System.out.println(----costTime: (endTime - startTime) 毫秒\t atomicIntegerMoney: bank.atomicIntegerMoney.get());startTime System.currentTimeMillis();for (int i 1; i threadNumber; i) {new Thread(() - {try {for (int j 1; j 100 * _1W; j) {bank.fieldUpdaterMoney(bank);}} finally {countDownLatch3.countDown();}},String.valueOf(i)).start();}countDownLatch3.await();endTime System.currentTimeMillis();System.out.println(----costTime: (endTime - startTime) 毫秒\t fieldUpdaterMoney: bank.fieldUpdaterMoney);}
}----costTime: 3513 毫秒 synchronizedMoney: 50000000 ----costTime: 816 毫秒 atomicIntegerMoney: 50000000 ----costTime: 1138 毫秒 fieldUpdaterMoney: 50000000 六、原子操作增强类
1、概述
原子操作增强类包含DoubleAccumulator、DoubleAdder、LongAccumulator、LongAdder。 LongAdder只能用于计算加法且只能从0开始计算LongAccumulator提供了自定义的函数操作。
《阿里巴巴Java开发手册中》
【参考】 volatile 解决多线程内存不可见问题。对于一写多读是可以解决变量同步问题但是如果多写同样无法解决线程安全问题。 说明 如果是 count操作使用如下类实现 AtomicInteger count new AtomicInteger(); count.addAndGet(1); 如果是 JDK8推荐使用 LongAdder 对象比 AtomicLong 性能更好减少乐观锁的重试次数。
在高并发下推荐使用原子操作增强类它提供了比原子操作类更好的性能。
2、LongAdder常用方法
LongAdder常用方法DoubleAdder类似。
// 将当前的value加x
void add(long x)// 将当前的value加1
void increment()// 将当前value减1
void decrement()// 返回当前值。特别注意在没有并发更新value的情况下sum会返回一个精确值在存在并发的情况下sum不包装返回精确值
long sum()// 将value重置为0可用于替代重新new一个LongAdder但此方法只可以在没有并发更新的情况下使用。
void reset()// 获取当前value并将value重置为0
long sumThenReset()3、LongAdder使用实例
LongAdder longAdder new LongAdder();
// 高并发下线程安全
longAdder.increment();
longAdder.increment();
longAdder.increment();System.out.println(longAdder.sum());4、LongAccumulator
LongAdder只能用于计算加法且只能从0开始计算LongAccumulator提供了自定义的函数操作。
LongAccumulator构造方法需要传入一个函数
public LongAccumulator(LongBinaryOperator accumulatorFunction,long identity) {this.function accumulatorFunction;base this.identity identity;
}LongBinaryOperator需要传入一个left、一个right并且有一个返回值
FunctionalInterface
public interface LongBinaryOperator {long applyAsLong(long left, long right);
}LongAccumulator的accumulate方法用于将传入的参数与当前的参数使用函数进行计算。
LongAccumulator longAccumulator new LongAccumulator(new LongBinaryOperator()
{Overridepublic long applyAsLong(long left, long right){return left right;}
},0);longAccumulator.accumulate(1);//0 1 1
longAccumulator.accumulate(3);//1 3 4System.out.println(longAccumulator.get());5、synchronized、AtomicLong、LongAdder、LongAccumulator性能对比
通过结果我们可以发现LongAdder、LongAccumulator在高并发场景下有着极高的性能数倍于AtomicLong。
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.concurrent.atomic.LongAdder;class ClickNumber //资源类
{int number 0;public synchronized void clickBySynchronized(){number;}AtomicLong atomicLong new AtomicLong(0);public void clickByAtomicLong(){atomicLong.getAndIncrement();}LongAdder longAdder new LongAdder();public void clickByLongAdder(){longAdder.increment();}LongAccumulator longAccumulator new LongAccumulator((x,y) - x y,0);public void clickByLongAccumulator(){longAccumulator.accumulate(1);}}/*** 需求 50个线程每个线程100W次总点赞数出来*/
public class AccumulatorCompareDemo
{public static final int _1W 10000;public static final int threadNumber 50;public static void main(String[] args) throws InterruptedException{ClickNumber clickNumber new ClickNumber();long startTime;long endTime;CountDownLatch countDownLatch1 new CountDownLatch(threadNumber);CountDownLatch countDownLatch2 new CountDownLatch(threadNumber);CountDownLatch countDownLatch3 new CountDownLatch(threadNumber);CountDownLatch countDownLatch4 new CountDownLatch(threadNumber);startTime System.currentTimeMillis();for (int i 1; i threadNumber; i) {new Thread(() - {try {for (int j 1; j 100 * _1W; j) {clickNumber.clickBySynchronized();}} finally {countDownLatch1.countDown();}},String.valueOf(i)).start();}countDownLatch1.await();endTime System.currentTimeMillis();System.out.println(----costTime: (endTime - startTime) 毫秒\t clickBySynchronized: clickNumber.number);startTime System.currentTimeMillis();for (int i 1; i threadNumber; i) {new Thread(() - {try {for (int j 1; j 100 * _1W; j) {clickNumber.clickByAtomicLong();}} finally {countDownLatch2.countDown();}},String.valueOf(i)).start();}countDownLatch2.await();endTime System.currentTimeMillis();System.out.println(----costTime: (endTime - startTime) 毫秒\t clickByAtomicLong: clickNumber.atomicLong.get());startTime System.currentTimeMillis();for (int i 1; i threadNumber; i) {new Thread(() - {try {for (int j 1; j 100 * _1W; j) {clickNumber.clickByLongAdder();}} finally {countDownLatch3.countDown();}},String.valueOf(i)).start();}countDownLatch3.await();endTime System.currentTimeMillis();System.out.println(----costTime: (endTime - startTime) 毫秒\t clickByLongAdder: clickNumber.longAdder.sum());startTime System.currentTimeMillis();for (int i 1; i threadNumber; i) {new Thread(() - {try {for (int j 1; j 100 * _1W; j) {clickNumber.clickByLongAccumulator();}} finally {countDownLatch4.countDown();}},String.valueOf(i)).start();}countDownLatch4.await();endTime System.currentTimeMillis();System.out.println(----costTime: (endTime - startTime) 毫秒\t clickByLongAccumulator: clickNumber.longAccumulator.get());}
} ----costTime: 4059 毫秒 clickBySynchronized: 50000000 ----costTime: 716 毫秒 clickByAtomicLong: 50000000 ----costTime: 73 毫秒 clickByLongAdder: 50000000 ----costTime: 57 毫秒 clickByLongAccumulator: 50000000 七、LongAdder源码分析
LongAdder为什么在高并发下保持良好性能LongAdder源码详细分析