java synchronized关键字在jvm中的实现原理

为了实现共享资源的线程安全,我们常常会使用synchronzied关键字来为资源加锁,在一个线程操作资源的时候,将资源锁住只供自己使用。这样保证了线程使用资源的同步,避免了对资源同时读写造成读写结果异常的情况。

那么,synchronized关键字在我们的jvm中具体是怎么实现的呢?

1.锁标志

当我们给一个变量或者方法加锁的时候,jvm是如何处理变量或者方法让它们有锁的呢?

1.1 synchronized使用方式

当我们使用synchronized关键字的使用方式不同,具体的效果也不同:

  • 当我们给一个普通方法加了synchronized关键字的时候,锁住的是这个方法所在类的实例对象
  • 当我们给一个static方法加锁的时候,锁住的是当前类的Class对象,如果不清楚Class对象是什么,请参见我的这篇博客:https://blog.csdn.net/qq_37856300/article/details/84854259
  • 当我们使用synchronized块的时候,锁住的是synchronized括号里的对象

清楚了上面三种锁的使用方式,可以发现三种方式锁的都是对象,那么问题就来了,jvm如何判断一个对象被锁了呢?

1.2 java对象头

如果一个对象被锁了,锁的信息是会存储在这个对象的对象头中的,什么是对象头呢?

每个java对象都有对象头,对象的对象头中存储着这个对象的信息,以32位jvm为例,一个对象的对象头是下图的结构的:
普通对象:
在这里插入图片描述
数组对象:
在这里插入图片描述

我们的锁信息就存储在图中的Mark Word中,Mark Word的结构如下图所示:
在这里插入图片描述

由此可见,jvm根据一个对象的对象头中的Mark Work来判断对象是否加锁,但是问题又来了,从上图中我们看到锁的状态可不止一种,而是足足有四种之多,其中的无锁状态不用多说,那么其它三种状态又是什么呢?

四种锁类型

我们使用synchronized关键字是为资源加一个锁,但是实际上synchronized会根据不同情况为资源自动选择不同的锁,在Java SE1.6中锁一共有4种状态,级别从低到高分别是无锁、偏向锁、轻量级锁、重量级锁,这几种状态会随着竞争情况逐渐升级,而且只可以升级但是不能降级降回来,这是为了提高获得锁和释放锁的效率。

1.偏向锁

HotSpot虚拟机的作者经过研究发现,大多数情况下,锁不存在多线程竞争,而且总是由同一线程多次获得。

如果在运行过程中,同步锁只有一个线程访问,不存在多线程争用的情况,则线程是不需要同步的,这种情况下,就会给线程加一个偏向锁。
如果在运行过程中,遇到了其他线程抢占锁,则持有偏向锁的线程会被挂起,JVM会消除它身上的偏向锁,将锁恢复到标准的轻量级锁。

当一个线程访问锁并获取锁的时候,会在对象头和栈帧中的锁记录中存储偏向锁偏向的线程的ID,以后该线程进出同步代码块的时候不需要进行CAS加锁解锁,只需要去看一眼加偏向锁的对象的Mark Word中存储的偏向线程ID是否等于当前访问的线程的ID。如果是,证明线程已经获得了锁;如果不是,先要去对象的MarkWord中看看当前是不是偏向锁,如果不是,就使用CAS竞争锁,如果是,就尝试使用CAS将对象的偏向锁偏向的线程ID改为当前线程的ID。

这一大段你可能已经看晕了,举个简单的例子,我们是老板,开了一家餐馆,一个老顾客老是来我们的餐馆吃饭,而且总要同样的菜,那么我们就记住了,下次就省去了给他点菜的过程,直接给他上他习惯点的菜就行了。什么时候他换口味了,老是吃别的一种菜,我们再记录他新的爱吃的菜就行了。用通俗的话来说就是,一个对象老是被相同的线程获得锁,那就记住这个线程,下次直接省去了获得锁释放锁的步骤,什么时候其它线程总是抢到锁了,再去记住别的线程。

2.轻量级锁

在轻量级锁加锁的时候,一条线程在执行同步代码块的之前,会先在自己的线程帧中创建存储锁记录的空间,然后将对象的Mark Word复制到锁记录中,接着会尝试使用CAS操作将锁住的对象的Mark Word替换为指向这条线程的锁记录的指针。如果替换成功了,当前线程获得轻量级锁,如果失败了,就会一次次地重复尝试获取锁,这叫做自旋,当自旋了很多次依然没有成功的时候,锁就会膨胀,膨胀为重量级锁,此时如果依然没有争夺到资源,线程就会进入阻塞状态。
当释放一个轻量级锁的时候,会使用CAS操作把之前在线程锁记录中存储的Mark Word替换回对象头,如果成功了,表示没有竞争发生,如果失败了,则表示当前锁存在竞争,于是此线程在释放轻量级锁的时候就会唤醒等待的线程。

所以,我们简简单单地使用了一个synchronized关键字,但是背后jvm使用了锁膨胀策略来优化,因为使用重量级锁是一种比较耗费性能的事。

猜你喜欢

转载自blog.csdn.net/qq_37856300/article/details/84558386