java 的锁是什么?
java 是基于对象的,每个对象都有一个mark word区域,即对象头区域,里面会有一个锁的字段,其实很简单,就是锁的模式是什么:偏向锁,轻量锁,重量锁,还有锁指向的指针
当一个线程,将锁的指针通过CAS指向自己的栈帧,就说明获得了锁
监视器是什么?
监视器只是实现同步的一种模式,他是依靠锁实现的
当java使用synchronize关键词时,转化到monitorenter和monitorexit这两个字节码指令,就是进入监视器和退出监视器,这其实只是一种模式,进入监视器的时候,就需要一个对象的引入,加锁首先要尝试获取对象的锁,获得就计数器加1,退出监视器则-1,就这么简单的实现了同步
不同等级锁的区别
首先最早的锁,就是阻塞block状态,被唤醒的时候涉及到用户态到核心态的转化,多线程时效率低,但后续优化后,目前synchronize效率已经和ReentrantLock差不多了
- 优化措施有:
自旋锁,锁消除,锁粗大
这三者都是jvm内部优化
1.自旋锁,因为阻塞的模式,会涉及用户态和核心态的转换,效率低,大部分情况下不需要阻塞那么久,所以会用自旋锁的方式,当线程拿不到锁时,会先尝试一定次数的自旋,如10次,如果还是拿不到锁,则会进入阻塞模式
2.锁消除
某些情况下,分析出不需要锁,内部会把锁消除
3.锁粗大
加锁一般是越精细越好,但这样会可能在一个类中不同方法 ,频繁获得锁和释放锁,某些情况下会被内部优化成对类或者对象进行加锁
- 不同的所类型有:
偏向锁,轻量锁,重量锁
不同的锁等级只是适用于不同的竞争环境,如果一般不怎么有竞争,则越轻越好,如果竞争概率很大,则直接最重的就好,这也是jvm的内部优化
总的来说,就是先偏向锁,有其他线程加锁,就变成轻量锁,轻量锁模式下,如果还有人来竞争,则变成重量锁。重量锁就是最普通的阻塞的方式
1.偏向锁
偏向锁是最轻的,也是最初时的尝试,当第一个线程通过CAS获得锁之后,以后这个线程再次获得这个锁,会直接去拿,不进行同步操作。直到另一个线程也来所得锁,就会修改偏向锁模式改为轻量锁
2.轻量锁
轻量锁仍然是为基本没有竞争的情况设计的,相比于偏向锁,他在每次获得锁时,都要通过CAS方式,去设置对象的mark word 锁只想当前栈帧,不会跳过这个同步操作。如果有两条以上的线程争用同一个锁,那轻量级锁就不再有效,要膨胀为重量级锁