当前位置 : 主页 > 编程语言 > java >

详解Java Synchronized的实现原理

来源:互联网 收集:自由互联 发布时间:2023-01-30
目录 Synchronized Synchronized的使用方式 Synchronized的底层实现 1.Java对象头 2.Monitor 3.线程状态流转在Monitor上体现 Synchronized 的锁升级 谈到多线程就不得不谈到Synchronized,重要性不言而喻,今
目录
  • Synchronized
  • Synchronized的使用方式
  • Synchronized的底层实现
    • 1.Java对象头
    • 2.Monitor
    • 3.线程状态流转在Monitor上体现
  • Synchronized 的锁升级

    谈到多线程就不得不谈到Synchronized,重要性不言而喻,今天主要谈谈Synchronized的实现原理。

    Synchronized

    synchronized关键字解决的是多个线程之间访问资源的同步性,synchronized 翻译为中文的意思是同步,也称之为”同步锁“。

    synchronized的作用是保证在同一时刻, 被修饰的代码块或方法只会有一个线程执行,以达到保证并发安全的效果。

    Synchronized的使用方式

    主要有3种使用方式:

    1.修饰实例方法:作用于当前实例加锁

    public synchronized void method(){
    
            // 代码
    
    }

    2.修饰静态方法:作用于当前类对象加锁

    public static synchronized void method(){
    
            // 代码
    
     }

    3.修饰代码块:指定加锁对象,对给定对象加锁

    synchronized(this){
    
      //代码                                  
    
     }

    Synchronized的底层实现

    synchronized的底层实现是完全依赖JVM虚拟机的,所以谈synchronized的底层实现,就不得不谈数据在JVM内存的存储:Java对象头,以及Monitor对象监视器。

    1.Java对象头

    在JVM虚拟机中,对象在内存中的存储布局,可以分为三个区域:

    • 对象头(Header)
    • 实例数据(Instance Data)
    • 对齐填充(Padding)

    Java对象头主要包括两部分数据:

    1)类型指针(Klass Pointer)

    是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例;

    2)标记字段(Mark Word)

    用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等等,它是实现轻量级锁和偏向锁的关键.

    所以,很明显synchronized使用的锁对象是存储在Java对象头里的标记字段里。

    2.Monitor

    monitor描述为对象监视器,可以类比为一个特殊的房间,这个房间中有一些被保护的数据,monitor保证每次只能有一个线程能进入这个房间进行访问被保护的数据,进入房间即为持有monitor,退出房间即为释放monitor。

    上图是syncrhoized同步代码块反编译截图,可以很清楚的看见,主要就是通过锁对象的monitor的取用(monitorenter)与释放来(monitorexit)实现的。

    3.线程状态流转在Monitor上体现

    当多个线程同时请求某个对象监视器时,对象监视器会设置几种状态用来区分请求的线程:

    • Contention List:所有请求锁的线程将被首先放置到该竞争队列
    • Entry List:Contention List中那些有资格成为候选人的线程被移到Entry List
    • Wait Set:那些调用wait方法被阻塞的线程被放置到Wait Set
    • OnDeck:任何时刻最多只能有一个线程正在竞争锁,该线程称为OnDeck
    • Owner:获得锁的线程称为Owner
    • !Owner:释放锁的线程

    下图反映了个状态转换关系:

    Synchronized 的锁升级

    锁解决了数据的安全性,但是同样带来了性能的下降,hotspot 虚拟机的作者经过调查发现,大部分情况下,加锁的代码不仅仅不存在多线程竞争,而且总是由同一个线程多次获得。

    所以基于这样一个概率,synchronized 在JDK1.6 之后做了一些优化,为了减少获得锁和释放锁来的性能开销,引入了偏向锁,锁的状态根据竞争激烈的程度从低到高不断升级。

    1.无锁

    无锁没有对资源进行锁定,所有的线程都能访问并修改同一个资源,但同时只有一个线程能修改成功。

    2.偏向锁

    偏向锁是JDK6中引入的一项锁优化,大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。

    偏向锁是指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁,降低获取锁的代价。

    3.轻量级锁

    是指当锁是偏向锁的时候,被另外的线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,从而提高性能。

    4.重量级锁

    指的是原始的Synchronized的实现,重量级锁的特点:其他线程试图获取锁时,都会被阻塞,只有持有锁的线程释放锁之后才会唤醒这些线程。

    到此这篇关于详解Java Synchronized的实现原理的文章就介绍到这了,更多相关Java Synchronized内容请搜索自由互联以前的文章或继续浏览下面的相关文章希望大家以后多多支持自由互联!

    上一篇:Java动态规划之丑数问题实例讲解
    下一篇:没有了
    网友评论