首页 > 编程知识 正文

Java高并发编程详解pdf(并发编程的艺术pdf)

时间:2023-05-05 15:29:22 阅读:88884 作者:853

什么是原子操作?

原子(atomic )从物化来理解是不可分割的最小粒子,原子操作是不可中断的一个或几个序列的操作。

为了提高

多核CPU如何实现原子操作?

计算机的处理速度,各CPU有自己的缓存(专用缓存),另外CPU内的总线具有仲裁机构和外部存储器的访问的转换和通信的作用,同样是为了发挥计算机的综合效率而提出的其处理器上的原子操作也基于锁定到缓存或锁定到总线的方法。

以使用总线锁保证原子性的I为例,多个处理器对共享变量I进行I操作时,显然此时不具有原子性。 因为操作结束后与期待值不一致。 例如,如果对i=1进行2次I操作,期待值有可能是3,但结果有可能是2。

这是因为多个处理器可能会获取自己缓存的值,并将每个值加1,然后直接写入主存储器。 怎么保证原子操作呢? 也就是说,你保证CPU1操作I对象的数据会被CPU2使用吗? 答案是锁定巴士。

总线锁定是指使用处理器提供的锁定#信号。 上一节对Lock组件进行了说明,如果有兴趣,请参阅。 当一个处理器向总线输出此信号时,如果其他处理器的请求被阻止,则该处理器可以独占共享内存。

另外,以I为例,在CPU1操作I时,向总线提供LOCK#信号,阻止其他处理器的CPU2操作共享变量I,在CPU2不能操作缓存了该共享变量的存储器地址的缓存的情况下,CPU

由于使用高速缓存锁保证原子锁定总线,其他处理器不能操作其他存储器地址的数据,所以锁定总线的开销比较大,现在处理器有时使用高速缓存锁代替总线锁来进行优化

“缓存锁定”是指,如果存储器区域缓存在处理器的缓存线上(缓存的最小操作单位),在锁定操作中被锁定,则如果执行锁定操作并写回到存储器中,则处理器会在总线上发出LOCK#信号,因此, 因为高速缓存完整性机制可以阻止两个或多个处理器同时修改高速缓存内存空间中的数据

同样在上面的示例中,如果CPU1更改了缓存线的I,并且变为I时使用了缓存锁,则CPU2不能同时缓存I的缓存线。 CPU1将值写入内存后,解除缓存锁定,其他CPU就可以再次缓存I的缓存线。

在Java中如何实现原子操作?

CAS (比较后设定)操作锁定CAS、JVM下的cas操作利用处理器提供的CMPXCHG指令实现。 下面的代码实现了基于CAS线程安全的计数器方法safeCount和非线程安全的计数器count。

执行结果如下。

974491

1000000

48

每次运行时,第一个值都会发生变化,第二个值是固定的。

JDK的合并订单中提供了支持原子操作的类,如原子布尔(原子更新的布尔值)、原子整数(原子长整型)原子更新的长整型值) 这些原子包装类还提供了方便的工具方法,如用原子方法将当前值从1增加或从1减少。 这些原子操作系统利用了volatile的特性(参照上一节java的同时艺术(2)-volatile )。 像原子集成器一样,引用源代码就可以发现。

CAS操作也有缺点,会引起三大问题。

ABA循环开销只保证一个共享变量ABA。 也就是说,一个值原来是a,变成b,又变成a。 使用CAS检查可以发现他没有变化,但实际上已经变化了。 这会引起ABA问题。 解决ABA问题的想法是使用版本号。 在变量之前添加版本号,每次变量更新时版本号加1,则ABA为1A2B3A。

循环开销,CAS是自旋,CAS实现的基本思路是循环进行直到CAS操作成功,所以自旋CAS一直不成功,会给CPU带来非常大的开销。

只能保证一个共享变量原子。 对一个共享变量执行操作时,我们可以使用循环CAS方法保证原子操作,但对多个共享变量执行操作时,循环CAS不能保证操作的原子性。 此时,可以使用锁定。

通过锁定机制,只有获取锁定的线程才能操作锁定的内存空间。 在JVM内部,实现了偏转锁定、轻量锁定、互斥锁定等各种锁定机制。 有趣的是,不仅是偏向锁定,JVM实现锁定的方式中还使用了循环CAS。 也就是说,线程想进入同步块时使用循环CAS方式获取锁定,退出同步块时使用循环CAS解除锁定。

下面介绍Java并发基本线程的知识。 有兴趣的可以添加关注,也可以欢迎转发,还可以在下面留言。 谢谢你。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。