Synchronized同步锁实现机制

Synchronized同步锁实现机制

synchronized关键字可以解决线程的安全问题,也就是在同一时间只有一个线程可以执行代码块,从而实现了同步互斥的目的

其实现依赖于JVM虚拟机,虚拟机也对其进行了优化,JVM将synchronized锁分为无锁、偏向锁、轻量级锁、重量级锁状态,JVM根据情况,进行锁升级。

首先先来了解一下对象头,毕竟就是通过对象头进行加锁操作

对象头:java对象在内存中存储的时候为了实现对象的一些额外功能,需要在对象中添加一些标记字段用来增强对象功能,而这些标记就组成了对象头。对象头中主要包括两部分数据:标记字段(Mark Word)和类型指针(class pointer),通过类型指针jvm可以知道这个对象是哪个类的实例;标记字段用来存储对象自身运行的数据,其中就包括锁对象的指针。

其底层是基于每个对象的(监视器)monitor来实现的,其中moniter的作用就是限制在同一时刻,只有一个线程可以进入monitor框定的一个临界区,从而达到线程的互斥操作。其中对象头中锁对象指针就是指向了一个monitor锁对象,线程在执行代码的时候需要获取monitor对象,执行完成之后释放该对象。 monitor锁本质又是依赖于操作系统的mutex lock进行实现,而操作系统进行线程间的切换就需要在用户态和内核之间进行切换,开销比较大,这就造成了重量级锁的的效率比较低

在大多数情况下,虽然我们加了Synchronized同步锁,但是或许在一个时间段,只有一个线程去执行这段代码,之后进行了一些优化,引入了偏向锁,轻量级,重量级锁

  1. 无锁:没有对资源进行锁定,所有的线程都可以访问这一资源,但是在同一时刻只有一个线程可以能够修改成功,其他修改失败的线程会一直进行尝试修改
  2. 偏向锁:在一段时间内,只有一个线程在执行这段代码,并没有其他的线程和它来竞争,那这一个线程每次获取锁和释放锁的这个开销是完全没有必要的,jvm虚拟机就将其优化为偏向锁。偏向锁在一个线程第一次访问的时候就将其id进行记录,如果下次判断还是这个线程就不会在加锁了,但是此时存在第二个线程,这个锁就会升级为轻量级锁
  3. 轻量级锁:当锁是偏向锁的时候,存在第二个线程对这段资源进行访问的时候,这个时候就睡升级为轻量级锁,第二个线程会自旋尝试获取锁,线程自旋就是在等待但是不会阻塞,不断的进行尝试,这个操作会消耗cpu,吞吐率较低,由于线程不需要挂起和唤醒这两种状态,执行速度就比较快。 但是当自选达到超过一定的次数,就会升级为重量级锁; 当一个线程已持有锁,另一个线程在自旋,而此时又有第三个线程来访时,轻量级锁也会升级为重量级锁。
  4. 重量级锁:重量级锁通过对象内部的监视器(monitor)实现,而其中 monitor 的本质是依赖于底层操作系统的 Mutex Lock实现,操作系统实现线程之间的切换需要从用户态切换到内核态,切换成本非常高

注意:锁只能升级不能降级

经验分享 程序员 微信小程序 职场和发展