Syncronized解析

作用:

)确保线程互斥的访问同步代码

)保证共享变量的修改能够及时可见

)有效解决重排序问题。

用法:

)修饰普通方法(锁是当前实例对象)

)修饰静态方法(锁是当前对象的Class对象)

)修饰代码块(锁是Synchonized括号里配置的对象)

底层实现原理:

方法和代码块都是基于进入和退出Monitor对象来实现方法同步和代码块同步,但两者的实现细节不一样。

(1)代码块同步是使用monitorenter和monitorexit指令实现,monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处

每个对象有一个监视器锁(monitor)。线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:

,该线程即为monitor的所有者。

、如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1.

,再重新尝试获取monitor的所有权。

执行monitorexit的线程必须是锁对象所对应的monitor的所有者。

,那线程退出monitor,不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去获取这个
monitor 的所有权。

(2)方法同步是使用ACC_SYNCHRONIZED标示符实现的

相对于普通方法,常量池中多了ACC_SYNCHRONIZED标示符。当方法调用时,将会检查方法的
ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor。在方法执行期间,其他任何线程都无法再获得同一个monitor对象。

讲jdk1.6锁优化前的前置知识



锁的状态保存在java对象头中,那对象头是什么?

块区域:对象头、实例数据、对齐补充。(jvm知识)

对象头结构如下:

CAS:Compare and Swap,比较并设置。用于在硬件层面上提供原子性操作。比较是否和给定的数值一致,如果一致则修改,不一致则不修改。

Synchronized在jdk1.6的优化



Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的。但是监视器锁本质又是依赖于底层的操作系统的Mutex
Lock(互斥锁)来实现的,这个成本非常高,这就是为什么Synchronized效率低的原因。因此,这种依赖于操作系统Mutex Lock所实现的锁我们称之为“重量级锁”。JDK中对Synchronized做的种种优化,其核心都是为了减少这种重量级锁的使用。JDK1.6以后,为了减少获得锁和释放锁所带来的性能消耗,提高性能,引入了“轻量级锁”和“偏向锁”。

锁的状态总共有四种:

1.重量级锁(依赖操作系统的互斥锁)

2.轻量级锁(在无竞争的情况下使用CAS操作去消除同步使用的互斥量,默认开始就是这个)

3.偏向锁(在无竞争的情况下把整个同步都消除掉,连CAS操作都不做了)

4.无锁状态

随着锁的竞争,锁可以从偏向锁升级到轻量级锁,再升级的重量级锁(但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级)

位的JDK为例:

无锁和重量级(操作系统的互斥锁)不用解释了,重点解释轻量级锁和偏向锁。

轻量级锁

时,膨胀为重量级锁。

轻量级锁解锁:轻量级解锁时,会使用原子的CAS操作来将栈帧中DisplacedMark Word替换回到对象头,如果成功,则表示没有竞争发生。如果失败,表示当前锁存在竞争,锁就会膨胀成重量级锁。

偏向锁

,偏向模式。

偏向锁加锁过程:

当锁对象第一次被线程获取的时候,虚拟机将会把对象头中的标志位设为“01”,即偏向模式。同时使用CAS操作把获取到这个锁的线程的ID记录在对象的Mark
Word之中,如果CAS操作成功,持有偏向锁的线程以后每次进入这个锁相关的同步块时,虚拟机都可以不再进行任何同步操作

偏向锁的撤销:

当有另外一个线程去尝试获取这个锁时,偏向模式就宣告结束。 根据锁对象目前是否处于被锁定的状态,撤销偏向(Revoke Bias)后恢复到未锁定(标志位为“01”)或轻量级锁定(标志位为“00”)的状态,后续的同步操作就如上面介绍的轻量级锁那样执行

三种锁状态的总结

相关的扩展:

1.  Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。

2.上文提到的偏向锁、轻量级锁都是jdk1.5到1.6的锁优化技术中的。锁优化技术还有如下:

适应性自旋:

互斥同步对性能最大的影响是阻塞的实现,因为挂起线程和恢复线程都是OS内核态完成的。那么使用自旋(即忙循环等待),不去阻塞地等待,这就是自旋锁技术。然而,自旋需要占用CPU时间,时间短还好,时间长了浪费性能,而适应性地根据同一个锁上的自旋时间及锁的拥有者状态决定时间,就是适应性自旋技术。

锁消除:

即时编译期运行时,有些代码上的同步,被检测到不可能存在数据竞争的锁,进行消除。检测依据来源于逃逸分析技术。

锁粗化:

如果一个方法里有A、B、C三句代码,都分别进行了三次Synchronized(this),其实没必要,反而增加了加锁解锁的消耗,这种情况会直接粗化为一个大Synchronized。

参考:

《深入理解Java虚拟机》

《Java并发编程艺术》

http://www.cnblogs.com/paddix/p/5405678.html

http://ifeve.com/java-synchronized/

最新文章

  1. oracle‘s package,function,proceture编译时无响应(解决)
  2. Three.js基础部分学习
  3. 如何理解C#委托
  4. phpcms v9 标签含义整理
  5. MMORPG大型游戏设计与开发(规范)
  6. linux重启和关闭系统命令
  7. Android在OnCreate中获取控件的宽度和高度
  8. [TimusACM][1258]程序员撞墙的问题
  9. K60的DMA多路脉冲计数
  10. Tomcat与web程序结构与Http协议
  11. 10.TCP连接的建立与终止
  12. shiro权限控制的简单实现
  13. sqlserver 查询 inner join 同一表2次 只出一条查询结果
  14. 计算机信息类ComputerInfo(车)
  15. 数据库-mysql命令
  16. 网络编程 -- RPC实现原理 -- NIO多线程 -- 迭代版本V2
  17. thinkphp如何省略index.php
  18. Oracle审计策略例子
  19. DLL动态链接库导出函数方法 -- 动态导出(.def文件导出)
  20. spring注入是否会被回收

热门文章

  1. 字符串和Date互相转化
  2. Python(Head First)学习笔记:五
  3. Python网络爬虫实战(一)快速入门
  4. Mars视频笔记——Animation
  5. VG有空间,创建逻辑卷
  6. Hive数据导入/导出
  7. 关于解决web编码问题的总结
  8. centos 7.x安装 jdk1.8
  9. 表达式树练习实践:C# 循环与循环控制
  10. 定义一个Person类,其中包括:1.定义属性:姓名、年龄、民族作为成员变量。定义静态成员变量:人数2.定义构造方法:对成员变量进行初始化。3.定义多个方法:分别显示相应的属性值,例如getName(){System.out.print("名称="+name+";"); }4.定义一个方法“成长”:实现年龄的增加,每执行一次年龄增加1