synchronized原理和锁优化

本文详细解析了synchronized关键字的工作原理,包括其字节码指令、线程安全性定义、原子性、可见性和有序性的保证方式,并介绍了锁自旋、锁消除等优化手段。
1 synchronized原理
synchronized关键字编译后会在同步块的前后添加上montorenter和monitorexit两个字节码指令,这两个字节码指令都需要一个指向锁定和解锁对象的reference,如果指定了同步的对象reference就指向这个对象,如果修饰的是方法,如果是类方法就指向Class对象,如果是实例方法就指向这个实例。
2线程安全
2.1定义
当多线程访问一个对象时,如果不需要考虑多线程的调度和交替执行,也不需要进行额外的同步,或者在调用方进行额外的协调操作,调用这个对象的行为都可以获得正确的结果,就可以说这个对象是线程安全的。

2.2原子性
java内存模型直接保证的原子性包括:read load use assign store write这6个,另外synchronized之间的操作也具备原子性。

2.3可见性
可见性指一个线程修改了共享变量的值,另外一个线程立即能够获得这个修改。
volatile通过修改后能够立即同步回主内存,使用之前必须从主内存刷新,保证了可见性。
synchronized和final变量也保证了可见性。

2.4有序性
同一个线程内,所有操作都是有序的,从一个线程观察另外一个线程,都是无序的。
synchronized 可以保证同一个锁的同步块只能串行进入。


3 synchronized缺点
synchronized是一种悲观锁,锁存的的问题:
1.多线程竞争的情况下,频繁的加锁解锁导致过多的线程上下文切换,由于java线程是基于操作系统内核线程实现的,所以如果阻塞或者唤醒线程都需要切换到内核态操作,这需要耗费许多CPU时钟。
2.一个线程持有锁,会导致其他请求该锁的线程挂起。
3.如果高优先级线程请求的锁,被低优先级线程占用,则会发生优先级倒置。

4锁优化
4.1 锁自旋
很多应用中共享数据的锁定,只会持续很多的一段时间,为了这很短的一段时间做线程的挂起和恢复,会造成很大的性能消耗,因为java线程对应操作系统的内核线程,要做挂起和恢复需要从用户态切换到通过系统调用完成,所以让后面请求锁的线程自旋一会。

4.2 锁消除
代码上要求同步,但是虚拟机检测到不存在共享数据竞争的情况下,会做锁消除。
有很多同步不是程序员自己加上的。

4.3 锁粗化
一般情况下锁应该范围尽可能的小。但是如果是循环内的锁,才可以通过锁粗化来避免频繁的加锁解锁消耗性能。
4.4 对象头
HotSpot虚拟机的对象头分为两部分,第一部分用于存储对象自身的运行时数据,如hashCode,GC分代年龄,官方称之为"mark word",第二部分用于存储指向方法区对象类型的指针,如果是数组类型的还有一个存储数组长度的部分。
其他状态下的mark word如下:

[img]http://dl2.iteye.com/upload/attachment/0104/0712/55e56721-135d-3618-8a04-2842a157e22b.png[/img]


4.5 偏向锁
Java SE1.6为了减少获得锁和释放锁所带来的性能消耗,引入了“偏向锁”和“轻量级锁”概念,Java SE1.6一共有4种状态,无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态,他们会随着竞争情况不断升级,锁可以升级但是不能降级。

锁对象第一次被线程获取的时候,虚拟机把对象头的标识位设置为"01",可偏向模式,如果通过CAS操作把mark word设置为当前线程的ID,如果CAS操作成功,这样以后这个线程每次进入这个锁的同步块时,虚拟机不再进行任何操作。

一旦有其他线程竞争这个锁,则偏向模式宣布结束。
4.6 轻量级锁
代码进入同步块时,如果对象没有被锁定,虚拟机首先在当前线程的栈帧建立一个名为lock record的记录,存储锁对象目前的mark word,官方称之为displaced mark word。然后虚拟机通过CAS操作将对象头的mark word更新为指向lock record,如果成功则该线程或得了锁,如果失败,则膨胀为重量级锁。

堆栈与对象的状态如下图所示:

[img]http://dl2.iteye.com/upload/attachment/0104/0710/101d8722-deb2-352f-b256-93cb14fefe55.png[/img]

4.7 各自的适用场景

[img]http://dl2.iteye.com/upload/attachment/0104/0714/be7c4eec-8cc7-3c58-baa6-8a3b754d1b65.png[/img]


5参考资料
http://www.infoq.com/cn/articles/java-se-16-synchronized
http://www.iteye.com/topic/806990
深入理解Java虚拟机:JVM高级特性与最佳实践 -周志明 *
http://blog.youkuaiyun.com/chenghai2011/article/details/8009983
http://wenku.baidu.com/link?url=mURhBANj9nJVdmtY9bfAnZ01qs-mTeeNZl_hF7TxAoiFW3sAoeaLGCIjcehTG7aSn0Ho_FApYB_raIKOdd0TaUI80T2tKCCbsVupLw4nduy *
http://zxf-noimp.iteye.com/blog/1050261
http://www.cnblogs.com/devinzhang/archive/2011/12/14/2287675.html
### Java 中 `synchronized` 关键字的实现原理 `synchronized` 是一种用于控制多个线程对共享资源访问的关键字,在 Java 编程语言中被广泛应用于解决并发编程中的数据竞争问题。当一个方法或一段代码块被声明为 `synchronized` 后,意味着同一时刻只有一个线程可以执行该部分代码。 具体来说,`synchronized` 的工作原理依赖于对象内部的一个监视器(Monitor)。每当有线程要进入被标记为 `synchronized` 的区域时,都需要先获取这个;而一旦离开此区域,则会释放掉持有的[^1]。 对于同步方法而言,如果是一个实例方法,那么就是当前对象本身 (`this`);如果是静态方法的话,则是对应类的 Class 对象。通过这种方式来确保任何时间点上最多只有一个线程能持有特定对象上的并执行相应的操作。 ### 升级机制 为了提高性能表现,JVM 设计了一套复杂的优化策略——即所谓的“升级”。这一过程大致分为以下几个阶段: #### 轻量级 (Lightweight Locking) 轻量级定是在没有争用的情况下采用的一种高效加协议。在这种模式下,每个尝试获得的操作都会直接检查目标对象头内的标志位,以此判断是否有其他活动线程正在占用这把。如果没有发现冲突,则可以直接设置自己的标识完成快速占有动作而不必陷入重量级的竞争状态。 #### 偏向 (Biased Locking) 偏向是针对大多数情况下只会在单一线程间传递的特点设计出来的进一步简化方案。首次成功请求到某对象之后,不仅会给其打上已定标签还会记录下最初拥有者的身份信息。此后只要还是同一个线程再次试图重新获取相同位置处的就可以免去重复验证流程从而加快速度。 #### 重量级 (Heavyweight Locking) 只有当以上两种较为温的方式都无法满足需求时才会真正进入到传统意义上的完全互斥等待队列里排队等候解通知。此时涉及到操作系统层面的支持,通常伴随着较高的上下文切换开销成本。 随着应用负载的变化情况,上述三种形式之间会发生动态转换:从无 -> 偏向 -> 轻量级 -> 最终演变为重量级的过程被称为“膨胀”。 ### Java 内存模型(JMM) 可见性保障 Java 内存模型规定了 JVM 如何处理多线程环境下的内存读写行为,并提供了必要的抽象层次使得开发者不必关心具体的硬件架构差异。其中一个重要特性便是保证了线程之间的 **可见性** :即某个线程所做的更改应当及时反映给其它可能观察这些变化的地方。 在涉及 `synchronized` 的场景中,每次退出临界区之前都要刷新本地缓存至主存之中,同时也会阻止编译期及运行时期内可能出现的危害程序逻辑正确性的指令重排序现象发生。因此即使存在不同的 CPU 核心或是处理器架构也能维持一致的行为特征[^2]。 ```java public class Counter { private int count; public synchronized void increment() { // 加入同步修饰符 this.count++; } public synchronized int getCount() { // 获取最新值也需要同步保护 return this.count; } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值