锁
加锁的目的:序列化访问临界资源 , 即同一时刻只有一个线程访问临界资源(同步互斥访问)
锁:隐式锁和显式锁
隐式锁:
Synchronized加锁机制
- Jvm 内置锁 , 不需要手动加锁和解锁
Jvm会自动加锁和解锁
- Synchronized加锁 几乎不可能跨方法加锁
显式锁
ReentrantLock 实现juc里的Lock .
实现基于AQS实现 , 需要手动加锁和解锁
ReentrantLock lock() , unlock()
- Synchronized 加锁的几种方式
- 方法加上关键字
1.1 静态方法上 加关键字(加锁加在类对象中)
1.2 非静态方法上加关键字(加在在当前
的类对象中)
- 实例方法(也就是普通方法)加上关键字
- 方法中使用同步代码块
跨方法的解锁
unsafe 的使用
synchronized 的使用与原理
- 加锁方式
- 同步实例方法 , 锁是当前的实例对象
- 同步类方法 , 锁是当前类对象
- 同步代码块 , 锁是括号里的对象
- 底层的原理
JVM 内置锁通过synchronized的使用, 通过内部对象Monitor(监视器锁)实现,基于进入与退出Monitor对象实现方法与代码块同步,监视器锁的实现依赖底层操作系统的Mutex lock(互斥锁)实现,它是一个重量级锁性能较低
- 每个对象都有一个自己的Monitor(监视器锁)
JVM 的加锁过程:
- 对象内存结构
- 对象头: 比如 hash码,对象所属的年代,对象锁,锁状态标志,偏向锁(线程)ID,偏向时间,数组长度(数组对象)等
- 对象实际数据:即创建对象时,对象中成员变量,方法等
- 对齐填充:对象的大小必须是8字节的整数倍
- 实例对象内存中存储在哪??
- 如果实例对象存储在堆区时:
实例对象内存在堆区,实例的引用存在栈上,实例的元数据class存在方法去或者元空间上
Object实例一定存在堆区的吗??
如果实例没有线程逃逸行为
对象内存图