码迷,mamicode.com
首页 > 其他好文 > 详细

synchronized与volatile

时间:2020-06-27 00:02:10      阅读:71      评论:0      收藏:0      [点我收藏+]

标签:适合   屏蔽   晚安   启动   影响   允许   优缺点   标识   修改   

说起多线程的两个修饰符,保证线程安全首先就会想到synchronized和voiltile这两个。

 

为什么会出现线程不安全?

多线程是相对cpu指令的,cpu本身是对一个又一个指令进行顺序执行的。多线程就是卡单个指令节点进行插入执行(这里说法估计有点问题,以后想起来再改吧)。jdk本身提供了对多个线程进行执行的支持。主要就是一个thread类提供,无论是实现runable接口还是集成thred类,本质顶层接口其实都是thred。而实现启动一个多线程的方式又多种多样,excutor线程池创建还是callabel还是thred,都是在cpu执行指令停滞区间进行的用时间换时间的操作,thredlocal这种可以理解为开辟了一个内存空间进行携带执行,这种叫做空间换时间。

 

多个线程多一个数据同时进行了操作,这就是所谓并发,当一个线程修改,而另一个线程也对其进行修改,彼此不可见,将会完成一个相对错误的结果,这种大概就是泛意义上的线程不安全吧。

 

synchronized

 

锁对象,是在对象的32位字符中,取前两位和当前线程的标识作为锁,泛意义上的锁对象。如果锁static则和锁this一样,指代当前.class对象。

 

所谓争抢synchronized锁,就是在当前线程拥有这个可执行权限时,进行执行下面的一段代码。

 

jvm本身只是进行了定义,没有其具体实现,jdk本身对他进行了实现。

jdk 1.5版本之前,它是直接采用经过cpu内核的重量级锁机制,进行线程间的同步。

jdk 1.5版本之后,它的实现分为三步:当一个对象锁定的时候,它会采用一个偏向锁(就是当前线程和对象id进行一个记录判断,如果是它直接放行)。从第二个开始,会有一个轻量级用户核的自旋锁(一个循环,在那边边等待边校验),直到第11次,它会锁升级为cpu内核的重量级锁。这也是锁升级的过程。锁降级?这个需要单写一下

 

这里补充一下轻量级锁和重量级锁使用的场景和优缺点:

轻量级锁虽然在用户核,但本质它是在cpu里面进行循环等待的,因此它是占用cpu资源的。所以适用于并发线程数不高,等待时间不长的场景。比如AQS里面大量使用轻量锁。

重量级锁本质就是释放cpu资源,让当前线程进入原就绪ready状态的等待队列,进行线程等待执行,它是不占用cpu资源的。适合并发量大,等待时间长的。

 

synchronized本身是可重入的,相当于一个i++操作。

synchronized不要用来锁定公用变量或使用率太高的对象,这样会导致锁资源卡cpu,导致系统缓慢。

 

voiltile

 

这个修饰符,说起来就是保证内存可见性和禁止指令重排序。

 

内存可见性

 

mesi,cpu的缓存一致性协议,这个涉及到大学的一些基础,先不在这里写。

简单的来说,就是当一个线程和另一个线程共同操作一个数据的时候,从cpu对各个线程的处理过程看,一个线程操作cpu的一个数据,cpu会先copy一份放入线程,线程对它进行改变,它会写入到cpu,但是另一个线程对它进行操作的时候,它可以见到这个数据改变,这就叫数据可见性把,我是这样理解的。

 

禁止指令重排

 

cpu对数据执行的时候,初始代计算机是对指令单个顺序执行操作,但是在现代计算机为了提高执行效率,在不改变运行结果的前提下,进行了一段并行计算,这叫指令重排。而cpu在多个线程操作的情况下,会出现重排结果影响的出现,cpu在处理这件事情的时候,加入了内存屏障。所谓内存屏障,就是在cpu进行并行计算时,加入loader和store这种指令组合,对单个指令进行一个屏蔽操作(我记得是这样的),这样就保证这个指令在计算时,不允许其他线程操作的进入,保证了当前指令的结果一致性。

 

先写到这,有时间再补充。晚安

 

synchronized与volatile

标签:适合   屏蔽   晚安   启动   影响   允许   优缺点   标识   修改   

原文地址:https://www.cnblogs.com/wangxiaobobo/p/13196684.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!