原子操作类之18罗汉增强
一、是什么
二、再分类
1.基本类型原子类
@Data
@AllArgsConstructor
@NoArgsConstructor
class MyNumber{
AtomicInteger atomicInteger=new AtomicInteger();
public void getAndPlus(){
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 = 0; i < SIZE; i++) {
new Thread(()->{
try{
for (int j = 0; j <1000; j++) {
myNumber.getAndPlus();
}
}finally {
countDownLatch.countDown();
}
},String.valueOf(i)).start();
}
//等待上面50个线程全部计算完成后,再去获得最终值
//try { TimeUnit.SECONDS.sleep(1); }catch (Exception e){e.getMessage();}
countDownLatch.await();
System.out.println(Thread.currentThread().getName() +" result "+ myNumber.atomicInteger.get());
}
}
main result 50000
2.数组类型原子类
3.引用类型原子类
AtomicStampedReference
AtomicMarkableReference
public class AtomicMarkableReferenceDemo {
static AtomicMarkableReference<Integer> markableReference=new AtomicMarkableReference(100,false);
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
boolean marked = markableReference.isMarked();
System.out.println(Thread.currentThread().getName()+" 默认标识 "+marked);
//暂停1秒钟线程,等待后面的t2线程和拿到一样的模式falg标识,都是false
try { TimeUnit.SECONDS.sleep(1); }catch (Exception e){e.getMessage();}
markableReference.compareAndSet(100,1000,marked,!marked);
},"t1").start();
new Thread(()->{
boolean marked = markableReference.isMarked();
System.out.println(Thread.currentThread().getName()+" 默认标识 "+marked);
//保证t1线程先执行完
try { TimeUnit.SECONDS.sleep(2); }catch (Exception e){e.getMessage();}
boolean b = markableReference.compareAndSet(1000, 2000, marked, !marked);
System.out.println(Thread.currentThread().getName()+" t2线程result "+b);
System.out.println(Thread.currentThread().getName()+" "+markableReference.isMarked());
System.out.println(Thread.currentThread().getName()+" "+markableReference.getReference());
},"t2").start();
}
}
t1 默认标识 false
t2 默认标识 false
t2 t2线程result false
t2 true
t2 1000
4.对象的属性修改原子类
①:使用目的
②:使用要求
@Data
@AllArgsConstructor
@NoArgsConstructor
class BankAccount{
//更新的对象属性必须使用public volatile修饰符
public volatile int totalMoney=0;//账户余额
String bankName="CCB";
AtomicIntegerFieldUpdater<BankAccount> fieldUpdater=
AtomicIntegerFieldUpdater.newUpdater(BankAccount.class,"totalMoney");
public void addMoney(int money){
totalMoney=totalMoney+money;
}
//不加synchronized,保证高性能原子性,局部微创小手术
public void transMoney(BankAccount bankAccount){
fieldUpdater.getAndIncrement(bankAccount);
}
}
/**
* 以一种线程安全的方式操作非线程安全对象的某些字段
*
* 需求
* 100个线程
* 每个线程转账100
* 不使用synchronized,尝试使用AtomicIntegerFieldUpdater来实现
*/
public class AtomicIntegerFieldUpdaterDemo {
public static void main(String[] args) throws InterruptedException {
BankAccount bankAccount = new BankAccount();
CountDownLatch countDownLatch=new CountDownLatch(100);
for (int i = 0; i < 100; i++) {
new Thread(()->{
try {
for (int j = 0; j < 100; j++) {
bankAccount.transMoney(bankAccount);
}
}finally {
countDownLatch.countDown();
}
},"t1").start();
}
countDownLatch.await();
System.out.println(bankAccount.totalMoney);
}
}
10000
@Data
@AllArgsConstructor
@NoArgsConstructor
class MyVar{
public volatile Boolean isInit=false;
AtomicReferenceFieldUpdater<MyVar,Boolean> fieldUpdater=
AtomicReferenceFieldUpdater.newUpdater(MyVar.class,Boolean.class,"isInit");
public void init(MyVar myVar){
if (fieldUpdater.compareAndSet(myVar,Boolean.FALSE,Boolean.TRUE)){
System.out.println(Thread.currentThread().getName()+" start init...");
try { TimeUnit.SECONDS.sleep(2); }catch (Exception e){e.getMessage();}
System.out.println(Thread.currentThread().getName()+" over init...");
}else {
System.out.println(Thread.currentThread().getName()+" 已经有线程在进行初始化工作...");
}
}
}
/**
* 需求
* 多线程并发调用一个类的初始化方法,如果未被初始化过,将执行初始化工作
* 要求只能被初始化一次,只要一个线程操作成功
*/
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();
}
}
}
1 start init...
2 已经有线程在进行初始化工作...
3 已经有线程在进行初始化工作...
4 已经有线程在进行初始化工作...
5 已经有线程在进行初始化工作...
1 over init...
5.原子操作增强类原理深度解析
点赞计数器,看看性能
public class LongAdderDemo {
public static void main(String[] args) {
//做乘法
LongAccumulator longAccumulator=new LongAccumulator((x,y)->x*y,2);
longAccumulator.accumulate(5);
System.out.println(longAccumulator.get());
//加法
LongAccumulator longAccumulator2=new LongAccumulator((x,y)->x+y,2);
longAccumulator2.accumulate(5);
System.out.println(longAccumulator2.get());
}
}
10
7
LongAdder高性能对比code演示
@Data
@AllArgsConstructor
@NoArgsConstructor
class ClickNumber{
int number=0;
AtomicLong atomicLong=new AtomicLong(0);
LongAdder longAdder=new LongAdder();
LongAccumulator longAccumulator=new LongAccumulator((x,y)->x+y,0);
public synchronized void clickBySynchronized(){
number++;
}
public void clickByAtomicLong(){
atomicLong.getAndIncrement();
}
public void clickByLongAdder(){
longAdder.increment();
}
public void clickByLongAccumulator(){
longAccumulator.accumulate(1);
}
}
/**
* 需求:50个线程,每个线程100w次,总点赞数出来
*/
public class AccumulatorCompareDemo {
public static void main(String[] args) throws InterruptedException {
ClickNumber clickNumber=new ClickNumber();
CountDownLatch countDownLatch1 =new CountDownLatch(50);
CountDownLatch countDownLatch2=new CountDownLatch(50);
CountDownLatch countDownLatch3=new CountDownLatch(50);
CountDownLatch countDownLatch4=new CountDownLatch(50);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 50; i++) {
new Thread(()->{
try{
for (int j = 0; j < 1000000; j++) {
clickNumber.clickBySynchronized();
}
}finally {
countDownLatch1.countDown();
}
}).start();
}
countDownLatch1.await();
long endTime = System.currentTimeMillis();
System.out.println("clickBySynchronized costTime "+(endTime-startTime) +" result "+clickNumber.number);
long startTime2 = System.currentTimeMillis();
for (int i = 0; i < 50; i++) {
new Thread(()->{
try{
for (int j = 0; j < 1000000; j++) {
clickNumber.clickByAtomicLong();
}
}finally {
countDownLatch2.countDown();
}
}).start();
}
countDownLatch2.await();
long endTime2 = System.currentTimeMillis();
System.out.println("clickByAtomicLong costTime "+(endTime2-startTime2) +" result "+clickNumber.number);
long startTime3 = System.currentTimeMillis();
for (int i = 0; i < 50; i++) {
new Thread(()->{
try{
for (int j = 0; j < 1000000; j++) {
clickNumber.clickByLongAdder();
}
}finally {
countDownLatch3.countDown();
}
}).start();
}
countDownLatch3.await();
long endTime3 = System.currentTimeMillis();
System.out.println("clickByLongAdder costTime "+(endTime3-startTime3) +" result "+clickNumber.number);
long startTime4 = System.currentTimeMillis();
for (int i = 0; i < 50; i++) {
new Thread(()->{
try{
for (int j = 0; j < 1000000; j++) {
clickNumber.clickByLongAccumulator();
}
}finally {
countDownLatch4.countDown();
}
}).start();
}
countDownLatch4.await();
long endTime4 = System.currentTimeMillis();
System.out.println("clickByLongAccumulator costTime "+(endTime4-startTime4) +" result "+clickNumber.number);
}
}
clickBySynchronized costTime 1820 result 50000000
clickByAtomicLong costTime 951 result 50000000
clickByLongAdder costTime 153 result 50000000
clickByLongAccumulator costTime 166 result 50000000
源码、原理分析
LongAdder为什么这么快
AtomicLong与LongAdder比较