文章目录
AtomicInteger
- AtomicXXX:CAS、unsafe.compareAndSwapInt
@ThreadSafe
@Slf4j
public class SafeCountAtomic {
public static int clientTotal = 5000;
public static int threadTotal = 200;
public static AtomicInteger count = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(threadTotal);
final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
for (int i = 0; i < clientTotal; i++) {
executorService.execute(() -> {
try {
semaphore.acquire();
add();
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
});
}
countDownLatch.await();
executorService.shutdown();
log.info("count:{}", count.get()); // 5000
}
private static void add() {
count.incrementAndGet();
// count.getAndIncrement();
}
}
源码分析
AtomicInteger.class
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
Unsafe.class
// 传入对象,
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
// 从主内存中获取到值
var5 = this.getIntVolatile(var1, var2);
// 将var1对象,工作内存中的值(var2)和主内存中的值(var5)比较,
// 如果相等,则将该值设置为( var5 + var4),
// 如果不相等,循环直到相等。
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
// 返回主内存中的值
return var5;
}
// JVM底层方法
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
AtomicLong和LongAdder
优劣分析:
CAS:如果竞争激烈的时候,会多次循环尝试,性能会受到一些影响
JVM对于普通类型的Long和Double变量,会将64位的读写操作拆成2个32位的操作
LongAdder在AtomicLong的基础上,将更新的压力分散,提高并行度,缺点,可能有误差。
选择:线程竞争激烈程度,高,选LongAdder,低,选AtomicLong
对数据的准确性要求高,选AtomicLong
package com.xiao.base.concurrent.atomic;
import com.xiao.base.concurrent.annotations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicLong;
/**
* @desc: 功能描述:()
* @author: jianjun.xiao
* @E-mail: xiaoxiao65535@163.com
* @createTime: 2018/9/28 16:40
*/
@ThreadSafe
@Slf4j
public class SafeCountAtomicLong {
public static int clientTotal = 5000;
public static int threadTotal = 200;
public static AtomicLong count = new AtomicLong(0);
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(threadTotal);
final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
for (int i = 0; i < clientTotal; i++) {
executorService.execute(() -> {
try {
semaphore.acquire();
add();
semaphore.release();
} catch (Exception e) {
e.printStackTrace();
}
countDownLatch.countDown();
});
}
countDownLatch.await();
executorService.shutdown();
log.info("count:{}", count.get());
}
public static void add() {
count.incrementAndGet();
}
}
package com.xiao.base.concurrent.atomic;
import com.xiao.base.concurrent.annotations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.LongAdder;
/**
* @desc: 功能描述:()
* @author: jianjun.xiao
* @E-mail: xiaoxiao65535@163.com
* @createTime: 2018/9/28 16:46
*/
@ThreadSafe
@Slf4j
public class SafeCountLongAdder {
public static int clientTotal = 5000;
public static int threadTotal = 200;
public static LongAdder count = new LongAdder();
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(threadTotal);
final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
for (int i = 0; i < clientTotal; i++) {
executorService.execute(() -> {
try {
semaphore.acquire();
add();
semaphore.release();
} catch (Exception e) {
}
countDownLatch.countDown();
});
}
countDownLatch.await();
executorService.shutdown();
log.info("count:{}", count);
}
public static void add() {
count.increment();
}
}
AtomicBoolean的CAS操作很有用(某段代码只执行一次)
package com.xiao.base.concurrent.atomic;
import com.xiao.base.concurrent.annotations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @desc: 功能描述:()
* @author: jianjun.xiao
* @E-mail: xiaoxiao65535@163.com
* @createTime: 2018/10/7 10:45
*/
@Slf4j
@ThreadSafe
public class SafeAtomicBoolean {
private static int clientTotal = 5000;
private static int threadTotal = 200;
private static AtomicBoolean isHappened = new AtomicBoolean(false);
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(threadTotal);
final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
for (int i = 0; i < clientTotal; i++) {
executorService.execute(() -> {
try {
semaphore.acquire();
happend();
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
});
}
countDownLatch.await();
executorService.shutdown();
log.info("{}", isHappened.get());
}
public static void happend() {
if (isHappened.compareAndSet(false, true)) {
log.info("execute");
}
}
}
AtomicReference
package com.xiao.base.concurrent.atomic;
import com.xiao.base.concurrent.annotations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.atomic.AtomicReference;
/**
* @desc: 功能描述:()
* @author: jianjun.xiao
* @E-mail: xiaoxiao65535@163.com
* @createTime: 2018/9/28 17:07
*/
@ThreadSafe
@Slf4j
public class SafeAtomicReference {
public static AtomicReference<Integer> num = new AtomicReference<>(0);
public static void main(String[] args) {
num.compareAndSet(0, 1); // 1
num.compareAndSet(0, 2); // no
num.compareAndSet(1, 3); // 3
num.compareAndSet(1, 4); // no
num.compareAndSet(3, 5); // 5
log.info("count:{}", num.get()); // 5
}
}
AtomicIntegerFieldUpdater
package com.xiao.base.concurrent.atomic;
import com.xiao.base.concurrent.annotations.ThreadSafe;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
/**
* @desc: 功能描述:()
* @author: jianjun.xiao
* @E-mail: xiaoxiao65535@163.com
* @createTime: 2018/10/7 10:29
*/
@ThreadSafe
@Slf4j
public class SafeAtomicIntegerFieldUpdater {
// AtomicIntegerFieldUpdater : 原子性更新某个对象的某个字段,该字段必须被volatile修饰,且不能为static
private static AtomicIntegerFieldUpdater<SafeAtomicIntegerFieldUpdater> updater
= AtomicIntegerFieldUpdater.newUpdater(SafeAtomicIntegerFieldUpdater.class, "count");
// 要更新的对象的值必须被volatile修饰
@Getter
private volatile int count = 100;
public static void main(String[] args) {
SafeAtomicIntegerFieldUpdater safeAtomicIntegerFieldUpdater = new SafeAtomicIntegerFieldUpdater();
if (updater.compareAndSet(safeAtomicIntegerFieldUpdater, 100, 200)) {
log.info("update success 1,count:{}", safeAtomicIntegerFieldUpdater.getCount());
}
if (updater.compareAndSet(safeAtomicIntegerFieldUpdater, 100, 200)) {
log.info("update success 2,count:{}", safeAtomicIntegerFieldUpdater.getCount());
} else {
log.info("update failed");
}
}
}
AtomicStampedReference(解决CAS的ABA问题)
解决方法:每次更新维护一个版本号
核心方法
// stamp : 每次更新的版本号
public boolean compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
Pair<V> current = pair;
return
expectedReference == current.reference &&
expectedStamp == current.stamp &&
((newReference == current.reference &&
newStamp == current.stamp) ||
casPair(current, Pair.of(newReference, newStamp)));
}