Java-- synchronized--学习原理总结
- monitor(重量级锁)
- 轻量级锁
- 加锁和解锁
- 锁膨胀
monitor(重量级锁)
synchronized 关键字在使用的时候,往往需要指定一个对象与之关联,例如 synchronized(this),或者 synchronized(obj),synchronized 如果修饰的是实例方法,那么其关联的对象实际上是 this,如果修饰的是类方法,那么其关联的对象是 this.class。总之,synchronzied 需要关联一个对象,而这个对象就是 monitor object。Java 对象模型中,所有的对象头部都有锁状态标记。偏向锁,轻量锁,重量锁都在Mark Word中都有锁标记或锁的地址,如果使用synchronized(重量级锁),该对象的Mark Word中就会设置指向monitor对象指针
比如我们现在有一个线程使用了synchronized(obj)(重量级锁情况)
会把MarkWord换为指向该monitor对象的指针,然后检查该monitor的Owner是否有值,如果有值说明被其他线程占用,进入EntryList进行等待
如果没有会直接占有Owner,然后开始运行临界区的代码,当他临界区的代码运行完毕,会把Owner置为空,然后去唤醒EntryList中等待的线程,其他线程开始非公平的竞争,谁拿到Owner谁执行,然后这样往复执行
注意:synchronized必须是进入同一个monitor对象才有上面所说的效果,不加synchronized的对象是无法关联到monitor锁
轻量级锁
加锁和解锁
轻量级锁的使用场景:如果一个对象虽然有多线程范围,但是多线程访问的时间是错开的,也就是说不存在竞争,轻量级锁的语法和重量级锁的语法一样都是synchronized(obj){},不用学习新的语法,当我们用线程的方式使用synchronized语法,这个时候方法的调用会产生一个线程调用方法的栈帧,栈帧里面就会有一个对应synchronized的LockRecord锁记录的对象
而lockRecord会记录锁对象的markWord,而Object reference就是这样锁对象的对应的指针,然后把lockRecord和锁对象的markWord进行替换把锁对象的markWord的值存入锁记录
这种情况就说明加锁成功,而加锁的线程操作完毕后又交换回来完成解锁,
如果发生了锁的重入 这里还会有一个锁记录重入的计数器
锁膨胀
如果一个线程0持有一个轻量级锁,这个时候又来一个线程1,这时候就发生了锁竞争,这个时候线程1就开始进入锁膨胀过程,去申请一个monitor(重量级锁)把锁对象的MarkWord替换成指向monitor的指针然后进入EntryList
开始等待把Owner设置为线程A,这个时候线程0替换回来发现这个的MarkWord不是自己的了(这个时候进入重量级锁的解锁过程)然后拿着这个指针找到monitor锁,然后把Owner设置为空,唤醒EntryList等待的线程完成解锁,