synchronized 是一种互斥锁,一次只能允许一个线程进入被锁住的代码块,synchronized 是java的一个关键字,
它能够将代码/方法锁起来, 如果synchronized是java的一个关键字,它能够将代码块/ 方法锁起来
如果synchronized 修饰的是实例方法,对应的锁则是对象实例
如果synchronized 修饰的是静态方法,对应的锁则是当前的Class 实例
如果synchronized 修饰的是代码块,对应的锁则是传入synchronized的对象实例
synchronized 的原理是通过反编译可以发现,当修饰方法时,编译器会生成AAC_SY NCHRONIZED 关键字用来标识
当修饰代码时,会依赖monitorenter 和monitorexit 指令 。无论synchronized 修饰的是方法还是代码块,对应的锁都是一个实例(对象),在内存中,对象一般由 3 部分组成,分别是对象头,对象实际数据和对齐填充,重点在于对象头,对象头又由几部分组成,但我们重点关注对象头Mark word 的信息,Mark word 会记录对象关于锁的信息,又因为每个对象会有一个与之对应的Monitor对象,monitor对象存储当前持有锁的线程以及等待锁的线程队列
偏向锁, 轻量级锁和重量级锁有什么区别?
偏向锁指的是JVM 会认为 只有某个线程才会执行同步代码(没有竞争的环境),此时会对偏向锁撤销,升级为轻量锁。在轻量锁级的状态下,当前线程会把栈帧下创建Lock Reconrd , LockRecord 会把Mark word的信息拷贝进去,且有个Owner 指针指向加锁的对象
线程执行到同步代码,则用CAS 试图 将mark Word 的指向到线程栈帧的LockRecord ,假设CAS 修改成功,则获取得到轻量级锁
假设修改失败,则自旋(重试),自旋一定次数后,则升级为重量级锁
简单的总结就是synchroized 锁原来只有重量级锁,依赖操作系统的mutex 指令,需要用户态和内核态切换,性能损耗十分明显,重量级锁用到monitor对象而偏向锁则在Mark word 记录线程Id 进行对比轻量级锁则是拷贝Mark Word 到Lock Record ,用CAS+ 自旋的方式获取
引入了偏向锁和轻量锁,就是为了再不同的使用场景使用不同的锁,进而提高效率,锁只有升级,没有降级,只有一个线程进入临界区,偏向锁;多个线程交替进入临界区,轻量级锁,多线程同时进入临界区,重量级锁