synchronized原理
它是JVM实现的锁,三大特性是:原子性,可见性,有序性。在使用上非常的方便,只需要在方法上加关键字,或者使用同步代码块的方式加锁即可。在JDK1.5
之前它只有重量级锁,之后Doug Lea在java层面实现了AQS,ReentrantLock
等性能优于synchronized,后续的jdk版本可能有来自Doug Lea的灵感增加了锁升级的过程(偏向锁,轻量级锁,重量级锁)性能得到了提升。
# markword
markword是JVM创建对象后在内存中的对象头的一部分结构,锁相关的数据会保存在里面,synchronized加锁其实就是对markword的数据进行修改实现,所以说synchronized是对象锁。
# 锁升级过程
锁升级的过程:无锁----偏向锁---轻量级锁---重量级锁
# 偏向锁
当markword还是无锁状态的时候,有一个线程过来加锁,直接通过cas的方式修改markword,把线程id设置到里面,并修改锁表设计为1。下一次还是同一个线程过来获取锁的时候,可直接获取锁,二如果是另外一个线程过来加锁,就需要升级为轻量级锁了。
这种加锁的方式的好处是不用经过上下文切换到内核,都是在用户态完成,加锁效率高。
# 轻量级锁
轻量级锁的 是在有线程竞争获取锁,但是竞争不激烈的情况下进行。比如两个线程交替获取锁。
当前线程试图去加锁,发现markword里标记了偏向锁,就会通过自旋+CAS的方式去加锁。加锁成功会在栈上创建一个锁表设计,markword中记录一个指针指向栈中的锁标记。
自旋默认的次数是10次,如果10次自旋失败后,进入重量级锁
# 重量级锁
进入重量级锁会创建一个MonitorObject对象,然后在markword里面的指针保存这个对象的地址,锁的信息保存在MonitorObject对象里面。重量级锁会发生上下文切换,所以非常消耗资源。
对象结构保存的信息如下:
MonitorObject{
Thread owner // 谁(线程)持有这个锁?
waiset // 等待队列,获取不到锁的线程在这里呆着
}
2
3
4