Java中的原子操作

您所在的位置:网站首页 什么叫操作变量 Java中的原子操作

Java中的原子操作

2024-07-11 14:38| 来源: 网络整理| 查看: 265

文章目录 1、什么是原子操作2、Java中原子操作的实现方式2.1 用CAS实现原子操作2.1.2 使用CAS实现原子操作2.1.3 CAS实现原子操作的问题 3、Java中使用锁实现原子操作4、CPU如何实现原子操作

1、什么是原子操作

原子操作:一个或多个操作在CPU执行过程中不被中断的特性

当我们说原子操作时,需要分清楚针对的是CPU指令级别还是高级语言级别。

比如:经典的银行转账场景,是语言级别的原子操作; 而当我们说volatile修饰的变量的复合操作,其原子性不能被保证,指的是CPU指令级别。 二者的本质是一致的。

“原子操作”的实质其实并不是指“不可分割”,这只是外在表现,本质在于多个资源之间有一致性的要求,操作的中间态对外不可见。

比如:在32位机器上写64位的long变量有中间状态(只写了64位中的32位);银行转账操作中也有中间状态(A向B转账,A扣钱了,B还没来得及加钱)

2、Java中原子操作的实现方式

Java使用锁和自旋CAS实现原子操作

2.1 用CAS实现原子操作 2.1.2 使用CAS实现原子操作 public class Counter { private final AtomicInteger atomicI = new AtomicInteger(0); private int i = 0; public static void main(String[] args) { Counter counter = new Counter(); ArrayList list = new ArrayList(1000); long start = System.currentTimeMillis(); IntStream.range(0, 100).forEach(u -> { list.add(new Thread(() -> IntStream.range(0, 1000).forEach(v -> { counter.safeCount(); counter.count(); }))); }); list.forEach(Thread::start); /* wait for all the threads to complete*/ list.forEach(u -> { try { u.join(); } catch (InterruptedException e) { e.printStackTrace(); } }); System.out.println(counter.i); System.out.println(counter.atomicI.get()); System.out.println(System.currentTimeMillis() - start); } /* 使用CAS 来实现原子操作*/ public void safeCount() { for (; ; ) { int i = atomicI.get(); /*Atomically sets the value to the given updated value if the current value == the expected value.*/ /*Parameters: expect - the expected value update - the new value*/ /* 其实,假如使用 原子类来实现计数器,不需要直接用 cas 的API,原子类已经提供了现成的API了*/ boolean success = atomicI.compareAndSet(i, i + 1); if (success) { break; } } } /* 使用 锁 来实现原子操作*/ public synchronized void safeCount1() { i++; } /* 线程不安全的累加*/ public void count() { i++; } }

并发包中提供了很多原子类来支持原子操作:

AtomicIntegerAtomicLongAtomicBooleanAtomicReferenceLongAdder 2.1.3 CAS实现原子操作的问题

CAS是并发包的基石,但用CAS有三个问题:

1)ABA问题 根源:CAS的本质是对变量的current value,期望值expected value进行比较,二者相等时,再将 给定值given update value设为当前值。

因此会存在一种场景,变量值原来是A,变成了B,又变成了A,使用CAS检查时会发现值并未变化,实际上是变化了。 对于数值类型的变量,比如int,这种问题关系不大,但对于引用类型,则会产生很大影响。

ABA问题解决思路:版本号。在变量前加版本号,每次变量更新时将版本号加1,A -> B -> A,就变成 1A -> 2B -> 3A。 JDK5之后Atomic包中提供了AtomicStampedReference#compareAndSet来解决ABA问题。

public boolean compareAndSet(@Nullable V expectedReference, V newReference, int expectedStamp, int newStamp) Atomically sets the value of both the reference and stamp to the given update values if the current reference is == to the expected reference and the current stamp is equal to the expected stamp. Parameters: expectedReference - the expected value of the reference newReference - the new value for the reference expectedStamp - the expected value of the stamp newStamp - the new value for the stamp

2)循环时间长则开销大 自旋CAS若长时间不成功,会对CPU造成较大开销。不过有的JVM可支持CPU的pause指令的话,效率可有一定提升。

pause作用:

延迟流水线指令(de-pipeline),使CPU不至于消耗过多执行资源。可避免退出循环时因内存顺序冲突(memorey order violation )引起CPU流水线被清空(CPU pipeline flush),从而提高CPU的执行效率。

3)只能保证一个共享变量的原子操作 CAS只能对单个共享变量如是操作,对多个共享变量操作时则无法保证原子性,此时可以用锁。

另外,也可“取巧”,将多个共享变量合成一个共享变量来操作。比如a=2,b=t,合并起来ab=2t,然后用CAS操作ab.

JDK5提供AtomicReference保证引用对象间的原子性,它可将多个变量放在一个对象中来进行CAS操作。

3、Java中使用锁实现原子操作

锁机制保证只有拿到锁的线程才能操作锁定的内存区域。 JVM内部实现了多种锁,偏向锁、轻量锁、互斥锁。不过轻量锁、互斥锁(即不包括偏向锁),实现锁时还是使用了CAS,即:一个线程进入同步代码时用自CAS拿锁,退出块的时候用CAS释放锁。 synchronized锁定的临界区代码对共享变量的操作是原子操作。

4、CPU如何实现原子操作

首先,CPU会自动保证基本的内存操作的原子性。CPU保证从内存中读写一个字节是原子的,即:当一个CPU读一个字节时,其他处理器不能访问这个字节的内存地址。 但对于复杂的内存操作如跨总线跨度、跨多个缓存行的访问,CPU是不能自动保证的。不过,CPU提供总线锁定和缓存锁定。

1、使用总线锁保证原子性

假如多个处理器同时读改写共享变量,这种操作(e.g. i++)不是原子的,操作完的共享变量的值会和期望的不一致。

原因:多个处理器同时从各自缓存读i,分别 + 1,分别写入内存。要想保证读改写共享变量的原子性,必须保证CPU1读改写该变量时,CPU2不能操作缓存了该变量内存地址的缓存。

总线锁就是解决此问题的。

总线锁:利用LOCK#信号,当一个CPU在总线上输出此信号,其他CPU的请求会被阻塞,则该CPU可以独占共享内存。

2、使用缓存锁保证原子性

同一时刻,其实只要保证对某个内存地址的操作是原子的即可,但总线锁定把CPU和内存间的通信锁住了。锁定期间,其他CPU不能操作其他内存地址的数据,所以总线锁定的开销比较大。目前CPU会在一些场景下使用缓存锁替代总线锁来优化。

频繁使用的内存会被缓存到L1、L2、L3高速cache中,原子操作可直接在高速cache中进行,不需要声明总线锁。 缓存锁是指:缓存一致性机制阻止同时修改由两个以上CPU缓存的内存区域数据,当其他CPU回写已被锁定的缓存行数据时,会使缓存行无效。

看下图:i 是同时被CPU1和CPU2缓存的内存区域变量;CPU1 修改缓存行中 i 时使用缓存锁定,则CPU2 不能同时缓存 i 的缓存行。(i 的缓存行会失效) [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TMdvKCO2-1618653147136)(http://note.youdao.com/yws/res/36381/WEBRESOURCE8d20b5f4eb06205db479ed38b76d5592)]



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3