Synchronized的原理与锁优化

本文详细解析了Java中synchronized关键字的实现原理,包括其在JVM层面的monitor机制,以及在1.6版本中引入的偏向锁、轻量级锁等优化措施,旨在帮助读者深入理解并发控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

并发变成中,synchronized一直都是元老级角色,它一直被称为重量级锁,在1.6中对synchronized进行各种优化过后才改善了它的性能消耗。为了降低synchronized的性能消耗引入了偏向锁,轻量级锁,以及JVM底层对锁存储结构的更改。

synchronized的使用

java中一切皆对象,每一个对象都可以作为锁,这是synchronized实现的基础,一般都隐氏的指定了锁的对象,所以平时使用时并没有指定参数,但是也可以显示的指定。

synchronized的使用如下:

  • 普通同步方法:锁是当前的实例对象,进入同步方法需要获取实例对象锁
  • 静态同步方法:锁是Class对象,需要获取Class对象锁才能访问
  • 同步方法块:锁是括号里的对象
   public void test(){
       Integer a =new Integer(1);
        //显示指定锁的对象
       synchronized (a){
           
       }
   }
    //静态方法,锁Class对象
   public synchronized static void get(){
       
   }
    //实例方法,锁实例对象
   public synchronized void set(){
       
   }

synchronized原理

synchronized在JVM层的实现是基于monitor的进入与退出的,monitor可以翻译成监视器或者管程,不过管程模型大家更加的熟悉,代码块的同步基于monitorenter和monitorexit指令,指令在编译后插入到相应的位置,这对指令必须成对存在。任何的对象都有一个对应的monitor对象,monitor被持有后,处于锁定状态。线程执行指令会尝试获取monitor的所有权,也就是获取对象的锁。

各位了解了对象的内存布局就知道对象头中存储着锁相关的信息,持有不同的锁,对象头的mark word内容不同,不过我一直有个疑问,monitor对象是用c++写的,monitor是存在哪里的呢?留着这个问题,继续往下说,JDK1.6前,synchronized是不推荐使用的,被称为重量级锁,1.6进行了各种优化,引入了级别从低到高的偏向锁、轻量级锁、重量级锁

偏向锁

大多数情况下,锁不仅不存在多线程竞争,而且总是同一线程多次获取,为了降低获取锁的代价,引入偏向锁。这里说下CAS,compareandswap,是一个原子操作,用来更新值,举个例子:如果 int a = 1,多个线程需要更改a的值,使用CAS能够解决并发问题主要包含以下操作,方法内,获取a的值赋值给c,即将要赋予a的值为b,先比较c与a是否相等,相等则a = b,否则其他线程改了a的值,重新进行cas操作。

线程访问同步块并获取锁时,在对象头和栈桢锁记录中保存锁偏向的线程ID,当本线程再次获取锁时,就不需要CAS的加锁和解锁,看一下mark word是否有指向当前线程的偏向锁。如果没有,看下mark word中是否是偏向锁,如果是使用CAS修改偏向锁修改为当前线程,如果不是偏向锁,使用CAS竞争锁,下图是流程:

轻量级锁

线程执行同步代码块之前,JVM将当前线程的栈桢中创建存储锁记录的空间,将对象头的mark word复制到锁记录,然后线程通过CAS将mark word替换为指向锁记录的指针,成功则获取到锁,失败自旋获取。流程图如下:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值