阅读本文约“3分钟”segmentfault
本文大体讲述两种线程实现的可见性,或许你已经提早想到了,那说明你的基础很好,咱们要聊聊synchronized实现可见性与volatile实现可见性。多线程
咱们会谈及几个点:指令重排序、as-if-serial语义、volatile使用注意事项等spa
首先咱们要了解下两个名词,有点术语的感受,虽然我不喜欢那些专业名词,可是你懂得···线程
可见性:通俗的说就是一个线程对共享变量值的修改,能够及时地被其它线程看到
共享变量:即一个变量在多个线程的工做内存中存在副本,则这个变量就是这些线程的共享变量排序
这两个名称理解起来还不算难,对吧?那么咱们来看看更加专业化的名词,我其实更但愿有具象化的有趣的名词来代替,原谅个人文学水平有限。图片
Java内存模型(JMM)内存
Java Memory Model 描述了Java程序中各类变量(这里指线程共享变量,你已经理解上面的第二个名词了)的访问规则,以及在JVM中将变量存储到内存和从内存中读取出变量这样的底层细节,就像细胞要在血管中流动同样(一个不及格的比喻),它要求全部的变量都存储在主内存中,每一个线程都有本身独立的工做内存,里面保存该线程使用到的变量的副本(也就是主内存中该变量的一份拷贝)get
让咱们来看看图型吧,文字有时理解起来比起图片要来的复杂,至少我是这样以为,我更喜欢具象化的说明同步
对于色调我一直有不一样于别人的理解,原谅我看似混乱的搭配。it
综合的总结一下,结合上图还有以前说的,咱们能够定出一下两个原则(或许能够轻松一点的说,而不是用“原则”)
一、线程对共享变量的全部操做都必须在本身的工做空间(内存)中进行,不能直接从主内存中读写
二、不一样线程之间没法直接访问其余线程中工做内存中的变量,线程间的变量值的传递须要经过主内存来完成
以上两句可能须要细细体会,就像你喝咖啡后不会立马喝下一口同样,请回味一下。
由此咱们能够模糊但又明确的指出共享变量可见性实现的原理
结合下图一同说明下,线程A对共享变量的修改要想被线程B即便看到,须要通过以下两步:
一、把工做内存A中更新过的共享变量刷新到主内存中
二、将主内存中最新的共享变量的值更新到工做内存B中
让咱们从新回到主题,Java语言层面支持的可见性实现方式:
——synchronized
——volatile
而由以上的篇幅讲解你也知道了实现共享变量的可见性,须要保证两点:
一、线程修改后的共享变量值可以及时从其工做内存中刷新到主内存中
二、其余线程可以及时把共享变量的最新值从主内存更新到本身的工做内存中
synchronized能够实如今于它的性质:原子性(同步性)、可见性
JMM(看到这个单词时或许你应该想到前面的中文含义)关于synchronized有这样的一些规定:
一、线程解锁前,必须把共享变量的最新值刷新到主内存中
二、线程加锁时,将清空工做内存中共享变量的值,在使用共享变量时须要从主内存中从新读取最新的值
(须要注意的是,加锁与解锁须要同一把锁,这让我想到了Redis,你想到了什么呢?)
咱们可精华的提高下,即线程解锁前对共享变量的修改在下次加锁时对其余线程是可见的
让咱们大体看看线程执行互斥代码(即以上的描述)的过程:
一、得到互斥锁
二、清空工做内存
三、从主内存拷贝变量的最新副本到工做内存
四、执行代码
五、将更改后的共享变量的值刷新到主内存
六、释放互斥锁
(请本身思考一次,不要把五、6步的顺序颠倒了哦)
本文未完~,请期待下篇。
【Java猫说】Java多线程以内存可见性(下篇)
欢迎你留言讨论属于你的看法,毕竟每一个人的味蕾都不同,这杯咖啡有吸引到你吗?
(好像又是一个槽糕的比喻)
本文已转载我的技术公众号:UncleCatMySelf
欢迎留言讨论与点赞
上一篇推荐:【Java猫说】主数据类型和引用
下一篇推荐:【Java猫说】Java多线程以内存可见性(下篇)