关于无锁的线程安全的整数,有以下三种
- AtomicInteger
- AtomicLong
- LongAdder
AtomicInteger
示例
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
public class AtomicClass {
public static AtomicInteger counter = new AtomicInteger();
public static Integer counter2 = 0;
public static Object mutex = new Object();
public static boolean useLock = false;
public static void main(String[] args) throws InterruptedException {
final Integer Thread_Amount = 20;
//1.创建线程池
ThreadPoolExecutor te = new ThreadPoolExecutor(Thread_Amount,Thread_Amount,0L,TimeUnit.SECONDS,
new LinkedBlockingDeque<>());
//2.创建线程任务
Callable<Long> task = () -> {
long start = System.currentTimeMillis();
if(useLock == false){
for(int k=0; k<100000; k++)
counter.incrementAndGet();
}else{
for(int k=0; k<100000; k++)
synchronized (mutex){
++counter2;
}
}
long end = System.currentTimeMillis();
return end - start;
};
// 在并发环境下CAS
useLock = false;
{
//3.创建线程
Future<Long>[] futures = new Future[Thread_Amount];
for(int i=0 ; i<Thread_Amount ; i++){
futures[i] = te.submit(task);
}
//4.获得线程结果
long totaltime = 0;
try {
for(int i=0 ; i<Thread_Amount ; i++)
totaltime += futures[i].get();
} catch (ExecutionException e) {
e.printStackTrace();
}
//5.打印结果
System.out.println("当不使用锁时花费时间:" + totaltime + "ms");
}
// 在并发环境下使用锁
useLock = true;
{
//3.创建线程
Future<Long>[] futures = new Future[Thread_Amount];
for(int i=0 ; i<Thread_Amount ; i++){
futures[i] = te.submit(task);
}
//4.获得线程结果
long totaltime = 0;
try {
for(int i=0 ; i<Thread_Amount ; i++)
totaltime += futures[i].get();
} catch (ExecutionException e) {
e.printStackTrace();
}
//5.打印结果
System.out.println("当使用锁时花费时间:" + totaltime + "ms");
}
//7.关闭线程池
te.shutdown();
}
}
console
当不使用锁时花费时间:413ms
当使用锁时花费时间:2168ms
将Thread_Amount改为50后的控制台输出:
当不使用锁时花费时间:723ms
当使用锁时花费时间:12023ms
可以看出,CAS的性能远高于锁,而且,随着线程数的增加,其性能差距会变得更大。
AtomicLong 与 LongAdder
其中LongAdder是jdk引进的,其性能远高于AtomicLong.
LongAdder的优化:
- 热点数据的分离(将对一个被频繁访问的数据的操作变成对一个数组的操作,再对数组求和得到应有的数据)
- 避免了伪共享(避免因其他变量修改而重新加载)
下面的代码可能涉及到高并发模型Future,详见笔记 链接
示例
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
//改注解可以解决伪共享问题
//@sun.misc.Contended
public class LongAdderTest {
static class MyTask implements Callable<Long> {
private static Object mutex = new Object();
private static Long counter = 0L;
private static AtomicLong aCounter = new AtomicLong(0);
private static LongAdder lCounter = new LongAdder();
/**
* state = 0,使用锁进行Long类型的共享
* state = 1,使用AtomicLong
* state = 2, 使用LongAdder
*/
private int state = 0;
private static int LIMIT = 10000000;
public MyTask(int state) {
this.state = state;
}
@Override
public Long call() {
long b = 0, e = 0;
if(state == 0){
b = System.currentTimeMillis();
for(int i=0 ; i<LIMIT ; i++){
synchronized (mutex){
++counter;
}
}
e = System.currentTimeMillis();
}else if(state == 1){
b = System.currentTimeMillis();
for(int i=0 ; i<LIMIT ; i++){
aCounter.incrementAndGet();
}
e = System.currentTimeMillis();
}else if(state == 2){
b = System.currentTimeMillis();
for(int i=0 ; i<LIMIT ; i++){
lCounter.increment();
}
e = System.currentTimeMillis();
}
return e - b;
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService ep = Executors.newFixedThreadPool(12);
Future<Long>[] futures = new Future[4];
for(int i=0 ; i<4 ; i++){
futures[i] = ep.submit(new MyTask(0));
}
Future<Long>[] futures2 = new Future[4];
for(int i=0 ; i<4 ; i++){
futures2[i] = ep.submit(new MyTask(1));
}
Future<Long>[] futures3 = new Future[4];
for(int i=0 ; i<4 ; i++){
futures3[i] = ep.submit(new MyTask(2));
}
long time = 0;
for(Future<Long> future : futures){
time += future.get();
}
System.out.println("Long类型花费时间:" + time + "ms");
time = 0;
for(Future<Long> future : futures2){
time += future.get();
}
System.out.println("AtomicLong类型花费时间:" + time + "ms");
time = 0;
for(Future<Long> future : futures3){
time += future.get();
}
System.out.println("LongAdder类型花费时间:" + time + "ms");
ep.shutdown();
}
}
console
Long类型花费时间:10079ms
AtomicLong类型花费时间:3597ms
LongAdder类型花费时间:1278ms