5.3 synchronized 原理
以重量级锁为例,比如 T0、T1两个线程同时执行加锁代码,已经出现了竞争(代码如下)
Plain Text
1synchronized(obj){//加锁
2
3}// 解锁
1.当执行到行1的代码时,会根据 obj的对象头找到或创建此对象对应的 Monitor 对象(C++对象)2.检查 Monitor 对象的 owner 属性,用 Cas 操作去设置 owner 为当前线程,Cas 是原子操作,只能有一个线程能成功
a.假设 T0 Cas 成功,那么 T0 就加锁成功,可以继续执行 synchronized 代码块内的部分b.T1 这边 Cas 失败,会自旋若干次,重新尝试加锁,如果
i.重试过程中 T0 释放了锁,则T1 不必阻塞,加锁成功
ii.重试时 T0 仍持有锁,则T1 会进入 Monitor 的等待队列阻塞,将来 T0 解锁后会唤醒它恢复运行(去重新抢锁)
5.4【追问】synchronized 锁升级
synchronized 锁有三个级别:偏向锁、轻量级锁、重量级锁,性能从左到右逐渐降低如果就一个线程对同一对象加锁,此时就用偏向锁
又来一个线程,与前一个线程交替为对象加锁,但只是交替,没有竞争,此时要升级为轻量级锁如果多个线程加锁时发生了竞争,必须升级为重量级锁
【说明】
·自java 6 开始对 synchronized 提供了锁升级功能,之前只有重量级锁但从java 15 开始,偏向锁被标记为已废弃,将来会移除(因为实际带来的性能提升不明显,某些情况下反而影向性能)
5.5 对比synchronized 和 volatile
并发编程需要从三个方面考虑线程安全,分别是:原子性、可见性、有序性·volatile 修饰共享变量,可以保证它的可见性和有序性,但不能保证原子性(JMM模型)·synchronized 代码块,不仅能保证共享变量的可见性、有序性,同时也能保证原子性PS.
,实际上用 volatie 去保证可见性和有序性,并不像上面那一句话描述的那么简单,可以参考黑马课程
5.6 对比 synchronized 和Lock
synchronized 是关键字,Lock 是Java 接
前者底层是 C++代码实现锁,后者是 Java 自己的代码来实现锁
·Lock 功能更多,比如可以选择是公平锁还是非公平锁、可以设置加锁超时时间、可打断等·Lock 的提供多种扩展实现(例如读写锁),可以根据场景选择更合适的实现
。Lock 释放锁需要调用 unlock 方法,而 synchronzied 在代码块结束无需显式调用就可以释放锁