synchronized的原子性
通过前面的篇章我们知道 synchronized 底层实际上通过JVM来实现的,同一时间只能有一个线程去执行synchronized 中的代码块。
原子性:既然同一时间只有一个线程去运行里面的代码,那么这个操作就是不能被其它线程打断的,所以这里天然就具有原子性了。
synchronized通过内存屏障保证可见性
老王:小陈啊,之前我们讲volatile的时候说过,volatile的可见性是通过什么来保证的?
小陈:这个我还记得啊,volatile是通过内存屏障来保证可见性的,Load屏障保证volatile变量每次读取数据的时候都强制从主内存读取;Store屏障每次volatile修改之后强制将数据刷新会主内存。
小陈:老王啊,难道说synchronized关键字也是通过内存屏障来保证可见性的?
老王:哈哈,小陈你的猜想没错。
我们都知道sychronized底层是通过monitorenter的指令来进行加锁的、通过monitorexit指令来释放锁的。
但是很多人都不知道的一点是,monitorenter指令其实还具有Load屏障的作用。
也就是通过monitorenter指令之后,synchronized内部的共享变量,每次读取数据的时候被强制从主内存读取最新的数据。
同样的道理monitorexit指令也具有Store屏障的作用,也就是让synchronized代码块内的共享变量,如果数据有变更的,强制刷新回主内存。
这样通过这种方式,数据修改之后立即刷新回主内存,其他线程进入synchronized代码块后,使用共享变量的时候强制读取主内存的数据,上一个线程对共享变量的变更操作,它就能立即看到了。
老王:画个图给你看一下,大概是这样子的:
小陈:原来是这样啊,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这两条指令其实就相当于复合指令,既具有加锁、释放锁的功能,同时也具有内存屏障的功能。
再画个图给你看一下,是怎么禁止重排序的:
小陈:老王啊,你真的是太太太厉害了......,小弟佩服得五体投地啊
小陈:少吹了,你按照我的并发文章目录的文章顺序学习下去,你也能达到这个地步,这可是当年我师父教给我的,我现在把它传给你了....
老王:小陈啊,今天的这篇是我们这边《练气篇》里的最后一篇了,讲完这个我们接下来就要进入《结丹篇》了,也就是意味着前面的篇章学完了之后,你底层的基础巩固得差不多了。
小陈:嘿嘿,经过前面两个阶段《筑基》、《练气》 的学习,我对底层的只是包括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并发专题《结丹篇》
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 读写锁怎么表示?
JAVA并发专题《元神篇》并发数据结构篇
31.CopyOnAarrayList 底层分析,怎么通过写时复制副本,提升并发性能?
32.ConcurrentLinkedQueue 底层分析,CAS 无锁化操作提升并发性能?
33.ConcurrentHashMap详解,底层怎么通过分段锁提升并发性能?
34.LinkedBlockedQueue 阻塞队列怎么通过ReentrantLock和Condition实现?
35.ArrayBlockedQueued 阻塞队列实现思路竟然和LinkedBlockedQueue一样?
36.DelayQueue 底层源码剖析,延时队列怎么实现?
37.SynchronousQueue底层原理解析
JAVA并发专题《飞升篇》线程池底层深度剖析
39.ThreadPoolExecutor 构造函数有哪些参数?这些参数分别表示什么意思?
40.内部有哪些变量,怎么表示线程池状态和线程数,看看道格.李大神是怎么设计的?
ThreadPoolExecutor execute执行流程?怎么进行任务提交的?addWorker方法干了啥?什么是workder?
ThreadPoolExecutor execute执行流程?何时将任务提交到阻塞队列? 阻塞队列满会发生什么?
ThreadPoolExecutor 中的Worker是如何执行提交到线程池的任务的?多余Worker怎么在超出空闲时间后被干掉的?
ThreadPoolExecutor shutdown、shutdownNow内部核心流程
再回头看看为啥不推荐Executors提供几种线程池?
ThreadPoolExecutor线程池篇总结