Atomic operation tools
Article directory
-
- Atomic operation tools
- 1. Test the efficiency of synchronize mutex locks and other atomic tool classes in modifying attributes
- 2. Integer array atomic operation tool class operates to modify the array
- 3. Integer atomic operation tools
- 4. Atomic integer field updater
- 5. Atomic reference field updater
- 6. Mark reference tool class
- 7. Long type atomic operation class and custom atomic binary operation function tool class
1. Test the efficiency of synchronize mutex locks and other atomic tool classes in modifying attributes
package com.bilibili.juc.atomics;
import lombok.Data;
import javax.lang.model.element.VariableElement;
import java.util.HashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.concurrent.atomic.LongAdder;
/**
* 测试synchronize和其他Long类型的原子操作工具类的效率
*/
class ClickNumber //资源类
{
int number = 0;
public synchronized void clickBySynchronized() {
number++;
}
//AtomicLong是采用的CAS执行的原子操作,在低并发效率还可以,高并发不行
AtomicLong atomicLong = new AtomicLong(0);
public void clickByAtomicLong() {
atomicLong.getAndIncrement();
}
//采用了一种分段的方式来处理原子操作。它将内部的数值分成多个段(Cells),每个段都有自己的原子计数。不同线程对不同的段进行增加操作,
// 减少了竞争,从而提高了性能。
LongAdder longAdder = new LongAdder();
public void clickByLongAdder() {
longAdder.increment();
}
//定义一个二元操作函数 ,x是当前值,y是accumulate()的值,初始值为0 0+1,1+1,2+1,3+1
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();
//50个线程,每个线程累加100万次
for (int i = 1; i <= threadNumber; i++) {
new Thread(() -> {
try {
for (int j = 1; j <= 100 * _1W; j++) {
clickNumber.clickBySynchronized();
}
} finally {
//每完成一次计数器减一,为0时停止阻塞
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 {
//每完成一次计数器减一,为0时停止阻塞
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 {
//每完成一次计数器减一,为0时停止阻塞
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());
}
}
Running results----costTime: 2559 milliseconds clickBySynchronized: 50000000
----costTime: 866 milliseconds clickByAtomicLong: 50000000 ----
costTime: 91 milliseconds clickByLongAdder: 50000000
----costTime: 55 milliseconds clickByLongAccumulator: 50000000Process finished with exit code 0
2. Integer array atomic operation tool class operates to modify the array
package com.bilibili.juc.atomics;
import java.util.concurrent.atomic.AtomicIntegerArray;
/**
* 整型数组原子操作工具类操作修改数组
*/
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+"\t"+atomicIntegerArray.get(0));
//给自定索引的数值加一
tmpInt = atomicIntegerArray.getAndIncrement(0);
System.out.println(tmpInt+"\t"+atomicIntegerArray.get(0));
}
}
operation result:
0
0
0
0
00 1122
1122 1123Process finished with exit code 0
3. Integer atomic operation tools
package com.bilibili.juc.atomics;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
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);
//50个线程,每个线程自增1000次,最后拿到打印结果50000
for (int i = 1; i <=SIZE; i++) {
new Thread(() -> {
try {
for (int j = 1; j <=1000; j++) {
myNumber.addPlusPlus();
}
} finally {
//每个线程执行完就会减一,计数器减到0就会停止阻塞
countDownLatch.countDown();
}
},String.valueOf(i)).start();
}
//等待上面50个线程全部计算完成后,再去获得最终值
//暂停几秒钟线程
//try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
//计数器减到0就会停止阻塞
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"\t"+"result: "+myNumber.atomicInteger.get());
}
}
Running result: main result: 50000
4. Atomic integer field updater
Used to operate integer fields in classes
package com.bilibili.juc.atomics;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
/**
* AtomicIntegerFieldUpdate 对类中的指定整型类型字段进行 原子自增操作
*/
class BankAccount//资源类
{
String bankName = "CCB";
//更新的对象属性必须使用 public volatile 修饰符。 JMM三大特性 原子性,可见性,有序性 ;volatile 不能保证原子性
public volatile int money = 0;//钱数
public void add()
{
money++;
}
//因为对象的属性修改类型原子类都是抽象类,所以每次使用都必须使用静态方法newUpdater()创建一个更新器,并且需要设置想要更新的类和属性。
AtomicIntegerFieldUpdater<BankAccount> 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()+"\t"+"result: "+bankAccount.money);
}
}
Running result: main result: 10000
5. Atomic reference field updater
package com.bilibili.juc.atomics;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
/**
* 原子引用字段更新器
*/
class MyVar //资源类
{
public volatile Boolean isInit = Boolean.FALSE;
//把指定isInit的操作变为原子操作
AtomicReferenceFieldUpdater<MyVar,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();
}
}
}
operation result:
1 ----- start init, need 2 seconds
2 ----- There is already a thread performing initialization work. . . . .
4 ----- There is already a thread performing initialization work. . . . .
3 ----- There is already a thread performing initialization work. . . . .
5 ----- There is already a thread performing initialization work. . . . .
1 ----- over init
6. Mark reference tool class
Use it to implement CAS (compare and swap)
package com.bilibili.juc.atomics;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicMarkableReference;
/**
标记引用工具类用来实现CAS
*/
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也是false),等待后面的T2线程和我拿到一样的模式flag标识,都是false
try {
TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {
e.printStackTrace(); }
//拿到期望的标识false ,把markableReference的标识设置为true
markableReference.compareAndSet(100,1000,marked,!marked);
boolean t1marked = markableReference.isMarked();
System.out.println("t1修改后的mark:"+t1marked);
},"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 beforeT2Update = markableReference.isMarked();
System.out.println(Thread.currentThread().getName()+"\t"+"修改前的标识:"+marked);
//如果 markableReference 中的引用是 100 且标志位的状态与 marked 变量相同,那么它将把引用更改为 2000,并将标志位的状态取反。
boolean b = markableReference.compareAndSet(100, 2000, marked, !marked);
System.out.println(Thread.currentThread().getName()+"\t"+"t2线程CAS修改result: "+b);
System.out.println(Thread.currentThread().getName()+"\t"+markableReference.isMarked());
System.out.println(Thread.currentThread().getName()+"\t"+markableReference.getReference());
},"t2").start();
}
}
/**
* CAS----Unsafe----do while+ABA---AtomicStampedReference,AtomicMarkableReference
*
* AtomicStampedReference,version号,+1;
*
* AtomicMarkableReference,一次,false,true
*
*/
operation result:
t1 Default mark: false
t2 Default mark: false
t1 modified mark: true
t2 Mark before modification: false
t2 t2 thread CAS modified result: false
t2 true
t2 1000Process finished with exit code 0
7. Long type atomic operation class and custom atomic binary operation function tool class
package com.bilibili.juc.atomics;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.LongBinaryOperator;
/**
Long类型原子操作类 采用了一种分段的方式来处理原子操作。它将内部的数值分成多个段(Cells),每个段都有自己的原子计数。不同线程对不同的段进行增加操作,
减少了竞争,从而提高了性能。
自定义原子二元操作函数工具类:LongAccumulator
*/
public class LongAdderAPIDemo
{
public static void main(String[] args)
{
LongAdder longAdder = new LongAdder();
longAdder.increment();
longAdder.increment();
longAdder.increment();
System.out.println(longAdder.sum());
//自定义原子二元操作函数工具类
LongAccumulator longAccumulator = new LongAccumulator(new LongBinaryOperator()
{
@Override
public long applyAsLong(long left, long right)
{
return left + right;
}
},0);
longAccumulator.accumulate(1);//1
longAccumulator.accumulate(3);//4
System.out.println(longAccumulator.get());
}
}
operation result:
3
4
Okay, the above are some commonly used atomic operation tool classes.