Java并发编程之synchronized原理分析

在理解synchronized原理之前,先理解什么是内置锁。

多线程的锁,其实本质上就是给一块内存空间的访问添加访问权限,因为Java中是没有办法直接对某一块内存进行操作的,又因为Java是面向对象的语言,万物皆对象,所以具体的体现就是某一个对象承担锁的功能,每一个对象都可以是一个锁。

内置锁,它是一个互斥锁,即最多只有一个线程能够获得该锁。使用方式就是使用 synchronized 关键字,synchronized 方法或者 synchronized 代码块。当线程A获得锁后才能执行方法,而其他线程则处于等待或者阻塞,直到A线程释放锁,若A线程不释放锁,其他线程则一直等待,保证了被synchronized修饰的方法或者代码块相当于原子性操作,保证了线程安全性。

1、当synchronized作用于普通(实例)方法是,内置锁对象是this(当前类的实例);

2、当synchronized作用于静态方法是,内置锁对象是当前类的Class字节码对象(类名.class);

3、当synchronized作用于代码块时,锁对象是synchronized(obj){}中的这个obj,obj只要是对象即可。

从jvm角度看synchronized

同步代码块中,进入同步代码块字节码为monitorenter,离开同步代码块字节码为monitorexit。

但在同步方法中并没有使用这两个字节码。

从操作系统角度看synchronized

Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的。但是监视器锁本质又是依赖于底层的操作系统的Mutex Lock(互斥锁)来实现的。操作系统实现线程之间的切换这就需要从用户态转换到核心态,这个成本非常高,状态之间的转换需要相对比较长的时间,这也就是为什么Synchronized效率低的原因。因此,这种依赖于操作系统Mutex Lock所实现的锁我们称之为“重量级锁”。

问:任何对象都可以作为锁,那么锁信息又存在对象的什么地方呢?

答:存在于对象头中,关于java对象的结构,我之前写了一篇文章《java对象的结构》

synchronized的执行过程: 
1. 检测Mark Word里面是不是当前线程的ID,如果是,表示当前线程处于偏向锁 
2. 如果不是,则使用CAS将当前线程的ID替换Mard Word,如果成功则表示当前线程获得偏向锁,置偏向标志位1 
3. 如果失败,则说明发生竞争,撤销偏向锁,进而升级为轻量级锁。 
4. 当前线程使用CAS将对象头的Mark Word替换为锁记录指针,如果成功,当前线程获得锁 
5. 如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。 
6. 如果自旋成功则依然处于轻量级状态。 
7. 如果自旋失败,则升级为重量级锁。

猜你喜欢

转载自blog.csdn.net/itcats_cn/article/details/81156988