赞
踩
Atomic
是原子性的意思,可以自动更新,用于原子增量计数器之类的应用程序。可以解决多线程环境递增的异议性问题。
AtomicInteger
Demopublic class Atomic { AtomicInteger integer = new AtomicInteger(0); @Test public void testAtomicInteger() throws InterruptedException { ExecutorService executor = new ThreadPoolExecutor(10, 50, 20, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10)); for (int i = 0; i < 100; i++) { executor.execute(this::add); TimeUnit.MILLISECONDS.sleep(1); } executor.shutdown(); } public void add() { for (int i = 0; i < 100; i++) { System.out.println(integer.incrementAndGet()); } } }
Atomic
Demopublic class IntDemo { int a = 1; @Test public void testInt() { final int[] int1 = {0}; ExecutorService executor = new ThreadPoolExecutor(10, 50, 20, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10)); for (int i = 0; i < 10; i++) { executor.execute(() -> { for (int j = 0; j < 10; j++) { int1[0]++; System.out.println(int1[0]); } }); } executor.shutdown(); } }
从运行结果来看,最终的结果不为100,可见在多线程的环境下,int自增操作并不是原子性的,这样就会导致一些问题。
以上程序的共享变量i
,没有进行锁、同步等数据一致性处理。变量i
会被从内存读取到CPU封装的L3缓存,如果在多线程环境下,会存在两个操作变量i
的线程同时跑在不同的核心上。
假设线程A->Core1,线程B->Core2,线程A从L3中读取到变量i
为0,线程B从L3中读取到变量i
也为0,线程A对变量i
++得到i=1
,同样线程B也对变量i
++得到i=1
,回写到内存时i=1
,但是实际上已经进行了两次的++
,故结果不正确。
特殊:四核八线程,对于一个核心,为了提高ALU的计算效率,会存在一个ALU单元对应两组Register,也就是所谓的超线程。此处的数据同步问题,博主还在学习。【如果有大佬了解,可以一起研究研究】
从以上的JMM模型的执行流程来看,当多线程的环境下,线程A和线程B可以同时读取主存中的变量,然后复制到本地工作内存中,接着计算,最后在将计算结果写回到主存中会存在数据不一致性。
在前文中,对于AtomicInteger递增是调用的incrementAndGet
从源码中可见,调用的是unsafe.getAndAddInt
,让我们来看看这个方法的实现。
从源码中可见,先是以getIntVolatile
的方法(native方法)获取变量的值,然后调用compareAndSwapInt
的方法(著名的CAS)进行数据的更改操作。
CAS(compare and swap),比较并交换。
如图,可知AtomicInteger继承了Number
抽象类,此抽象类中定义了一些关于数字之间的一些基础操作,具体方法如下图。
get
:获取value
set
:设置value
lazySet
:异步设置value
getAndSet(int newValue)
:将变量值设置成newValue,并返回旧值。compareAndSet(int expect, int update)
:比较并设置值,只有当原有的value=expect时,才会将变量值设置成update,返回操作结果。weakCompareAndSet
:与compareAndSet(int expect, int update)
类似,但是不强制原子性。getAndIncrement()
:原子递增,返回旧值。getAndDecrement()
:原子递减,返回旧值。getAndAdd(int delta)
:原子增加delta,返回旧值。incrementAndGet()
:原子递增,返回新值。decrementAndGet()
:原子递减,返回新值。addAndGet(int delta)
:原子增加delta,返回新值。getAndUpdate(IntUnaryOperator updateFunction)
此方法会先获取之前的值,然后将updateFunction
函数作用于之前的读取出来的值,最后将变量设置成计算得到的结果。此方法返回操作之前的旧值。
updateAndGet(IntUnaryOperator updateFunction)
此方法会先获取之前的值,然后将updateFunction
函数作用于之前的读取出来的值,最后将变量设置成计算得到的结果。此方法返回操作之后的新值。
getAndAccumulate(int x, IntBinaryOperator accumulatorFunction)
此方法会先获取之前的值,然后将accumulatorFunction
函数作用于之前的读取出来的值(其实就是将之前的旧值+x),最后将变量设置成计算得到的结果。此方法返回操作之前的旧值。
accumulateAndGet(int x, IntBinaryOperator accumulatorFunction)
此方法会先获取之前的值,然后将accumulatorFunction
函数作用于之前的读取出来的值(其实就是将之前的旧值+x),最后将变量设置成计算得到的结果。此方法返回操作之后的新值。
总结:对于get在方法名称前面的话,那么会返回操作之前的旧值。如果子啊方法名称后面,那么会返回操作之后的新值
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。