13.synchronized总结:怎么保证可见性、有序性、原子性?

2023年 9月 29日 35.5k 0

synchronized的原子性

通过前面的篇章我们知道 synchronized 底层实际上通过JVM来实现的,同一时间只能有一个线程去执行synchronized 中的代码块。

原子性:既然同一时间只有一个线程去运行里面的代码,那么这个操作就是不能被其它线程打断的,所以这里天然就具有原子性了。

image.png

synchronized通过内存屏障保证可见性

老王:小陈啊,之前我们讲volatile的时候说过,volatile的可见性是通过什么来保证的?

小陈:这个我还记得啊,volatile是通过内存屏障来保证可见性的,Load屏障保证volatile变量每次读取数据的时候都强制从主内存读取;Store屏障每次volatile修改之后强制将数据刷新会主内存。

小陈:老王啊,难道说synchronized关键字也是通过内存屏障来保证可见性的?

老王:哈哈,小陈你的猜想没错。

我们都知道sychronized底层是通过monitorenter的指令来进行加锁的、通过monitorexit指令来释放锁的。

但是很多人都不知道的一点是,monitorenter指令其实还具有Load屏障的作用。

也就是通过monitorenter指令之后,synchronized内部的共享变量,每次读取数据的时候被强制从主内存读取最新的数据。

同样的道理monitorexit指令也具有Store屏障的作用,也就是让synchronized代码块内的共享变量,如果数据有变更的,强制刷新回主内存。

这样通过这种方式,数据修改之后立即刷新回主内存,其他线程进入synchronized代码块后,使用共享变量的时候强制读取主内存的数据,上一个线程对共享变量的变更操作,它就能立即看到了。

老王:画个图给你看一下,大概是这样子的:

image.png

小陈:原来是这样啊,synchronized底层竟然也是通过内存屏障来保证可见性的。

synchronized使用内存屏障来保证有序性

老王:那我再问你,synchronizd是怎么保证有序性的,想必聪明如你,已经知道答案了吧

小陈:哈哈,之前volatile通过内存屏障来保证有序性的,我想synchronized也是吧。

老王:之前我们讲过,四条禁止指令重排序的内存屏障,不记得话,要记得看一下之前的篇章哦,这4条禁止重排序的内存屏障分别为:

StoreStore屏障:禁止StoreStore屏障的前后Store写操作重排

LoadLoad屏障:禁止LoadLoad屏障的前后Load读操作进行重排

LoadStore屏障:禁止LoadStore屏障的前面Load读操作跟LoadStore屏障后面的Store写操作重排

StoreLoad屏障:禁止LoadStore屏障前面的Store写操作跟后面的Load/Store 读写操作重排

同样的道理啊,也是通过monitorenter、monitorexit指令嵌入上面的内存屏障;monitorenter、monitorexit这两条指令其实就相当于复合指令,既具有加锁、释放锁的功能,同时也具有内存屏障的功能。

再画个图给你看一下,是怎么禁止重排序的:

image.png

小陈:老王啊,你真的是太太太厉害了......,小弟佩服得五体投地啊

小陈:少吹了,你按照我的并发文章目录的文章顺序学习下去,你也能达到这个地步,这可是当年我师父教给我的,我现在把它传给你了....

老王:小陈啊,今天的这篇是我们这边《练气篇》里的最后一篇了,讲完这个我们接下来就要进入《结丹篇》了,也就是意味着前面的篇章学完了之后,你底层的基础巩固得差不多了。

小陈:嘿嘿,经过前面两个阶段《筑基》、《练气》 的学习,我对底层的只是包括CPU缓存模型、JAVA内存模型、volatile底层原理、内存屏障、synchronized的底层原理、synchronized底层加锁过程、锁升级过程、Mark Word、monitor的锁原理等等都了解得比以前深入太多了,哈哈,这都多亏了老王啊

小陈:这让我对接下来要讨论的内容越发的期待起来了啊,哈哈......

老王:前面的只是还有不懂的,要记得回去再看下哦.

我们目前《筑基》、《练气》两篇目前就到这里了,你在修炼之路上基础也打得差不多了。所以你要准备一下,需要一支翡翠神竹、一枚金菩果,以此来进入下一个境界《结丹》。

小陈:好的,老王,我们下一篇见。

目录

JAVA并发专题 《筑基篇》

1.什么是CPU多级缓存模型?

2.什么是JAVA内存模型?

3.线程安全之可见性、有序性、原子性是什么?

4.什么是MESI缓存一致性协议?怎么解决并发的可见性问题?

JAVA并发专题《练气篇》

5.volatile怎么保证可见性?

6.什么是内存屏障?具有什么作用?

7.volatile怎么通过内存屏障保证可见性和有序性?

8.volatile为啥不能保证原子性?

9.synchronized是个啥东西?应该怎么使用?

10.synchronized底层之monitor、对象头、Mark Word?

11.synchronized底层是怎么通过monitor进行加锁的?

12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁

13.synchronized怎么保证可见性、有序性、原子性?

JAVA并发专题《结丹篇》

  • JDK底层Unsafe类是个啥东西?
  • 15.unsafe类的CAS是怎么保证原子性的?

    16.Atomic原子类体系讲解

    17.AtomicInteger、AtomicBoolean的底层原理

    18.AtomicReference、AtomicStampReference底层原理

    19.Atomic中的LongAdder底层原理之分段锁机制

    20.Atmoic系列Strimped64分段锁底层实现源码剖析

    JAVA并发专题《金丹篇》

    21.AQS是个啥?为啥说它是JAVA并发工具基础框架?

    22.基于AQS的互斥锁底层源码深度剖析

    23.基于AQS的共享锁底层源码深度剖析

    24.ReentrantLock是怎么基于AQS实现独占锁的?

    25.ReentrantLock的Condition机制底层源码剖析

    26.CountDownLatch 门栓底层源码和实现机制深度剖析

    27.CyclicBarrier 栅栏底层源码和实现机制深度剖析

    28.Semaphore 信号量底层源码和实现机深度剖析

    29.ReentrantReadWriteLock 读写锁怎么表示?

  • ReentrantReadWriteLock 读写锁底层源码和机制深度剖析
  • JAVA并发专题《元神篇》并发数据结构篇

    31.CopyOnAarrayList 底层分析,怎么通过写时复制副本,提升并发性能?

    32.ConcurrentLinkedQueue 底层分析,CAS 无锁化操作提升并发性能?

    33.ConcurrentHashMap详解,底层怎么通过分段锁提升并发性能?

    34.LinkedBlockedQueue 阻塞队列怎么通过ReentrantLock和Condition实现?

    35.ArrayBlockedQueued 阻塞队列实现思路竟然和LinkedBlockedQueue一样?

    36.DelayQueue 底层源码剖析,延时队列怎么实现?

    37.SynchronousQueue底层原理解析

    JAVA并发专题《飞升篇》线程池底层深度剖析

  • 什么是线程池?看看JDK提供了哪些默认的线程池?底层竟然都是基于ThreadPoolExecutor的?
  • 39.ThreadPoolExecutor 构造函数有哪些参数?这些参数分别表示什么意思?

    40.内部有哪些变量,怎么表示线程池状态和线程数,看看道格.李大神是怎么设计的?

  • ThreadPoolExecutor execute执行流程?怎么进行任务提交的?addWorker方法干了啥?什么是workder?

  • ThreadPoolExecutor execute执行流程?何时将任务提交到阻塞队列? 阻塞队列满会发生什么?

  • ThreadPoolExecutor 中的Worker是如何执行提交到线程池的任务的?多余Worker怎么在超出空闲时间后被干掉的?

  • ThreadPoolExecutor shutdown、shutdownNow内部核心流程

  • 再回头看看为啥不推荐Executors提供几种线程池?

  • ThreadPoolExecutor线程池篇总结

  • 相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论