关于无锁的线程安全的整数,有以下三种
- 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;};// 在并发环境下CASuseLock = 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.Contendedpublic 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;}@Overridepublic 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类型花费时间:10079msAtomicLong类型花费时间:3597msLongAdder类型花费时间:1278ms
