Java synchronized底层实现原理以及锁优化

Java中的synchronized关键字用于保证同步访问,避免出现多线程并发访问共享资源的问题,保证程序的正确性和一致性。在JVM中,synchronized的实现原理是通过Java对象头中的一个有关锁的标识位来实现的,具体的底层实现原理如下:

Java对象头

Java对象在堆中的数据结构是由对象头和实例数据两部分组成的,其中对象头占用了8个或者12个字节(64位JVM为12字节,32位JVM为8字节)。JVM对象头中主要包含了两部分信息:对象的hashCode以及对象的锁信息,锁信息主要有以下内容:

  • Mark Word:存储对象的标志位信息,主要有锁状态及一些标志位;
  • Klass Pointer:指向该对象对应的类元信息指针。

synchronized的实现原理

synchronized 关键字可以用来修饰普通方法、静态方法和代码块,这里主要讲解普通方法的synchronized实现原理。

普通方法的synchronized底层实现主要包含四个步骤:

  1. 当线程A来执行synchronized修饰的方法时,首先会检查该方法的锁状态是否处于 ''Unlocked" 状态;
  2. 如果处于 ''Unlocked" 状态,线程A则会获得该方法所对应对象的锁并将锁的状态设置为 ''Locked";
  3. 如果处于 ''Locked" 状态,线程A就会进入同步队列(等待队列);因为该方法是被synchronized修饰的,只能被一个线程执行,因此如果有多个线程来调用该方法,则会进入同步队列中阻塞等待执行;
  4. 当同步队列中线程的锁状态被释放时,唤醒队列中的线程,然后其中一条线程再次尝试获取该方法所对应对象的锁并将锁的状态设置为 ''Locked",取得锁的线程进入执行状态,其他线程仍然进入同步队列中等待。

锁优化

由于synchronized在实现同步的时候会带来一定的系统开销和调度开销,因此,JVM提供了一些锁优化来提高程序的执行效率,其中包括:

自旋锁

自旋锁是通过循环CAS(Compare-And-Swap)操作实现的,当线程发现自己要获取的锁已经被其他线程获取时,它不会马上进入阻塞状态,而是采用循环的方式不断尝试获取锁(重试),直到获取锁成功或者达到一定重试次数为止。自旋锁适用于锁竞争情况不是很激烈的场景。

锁消除

在程序执行过程中,如果JVM发现某些锁不会被多线程访问,那么JVM就会自动把锁消除掉,从而避免不必要的锁竞争。

例如:

public String getString(String str1, String str2) {
    StringBuffer stringBuffer = new StringBuffer();
    stringBuffer.append(str1).append(str2);
    return stringBuffer.toString();
}

上述代码中,由于StringBuffer对象只会在当前方法中使用,并不会被其他的线程访问,因此JVM可以自动把该方法中的锁消除掉,从而提高方法的执行效率。

轻量级锁

轻量级锁是为了避免线程在执行同步代码块时频繁地进入阻塞状态而引入的一种优化方式。JVM使用CAS操作,把当前线程的锁对象的MarkWord复制到线程的本地变量中,然后再尝试用CAS操作将线程本地变量的MarkWord替换回原对象的MarkWord。

偏向锁

偏向锁是JVM提供的一种轻量级锁优化策略,它适用于哪些只会有一个线程访问的情况。偏向锁的核心思想是:如果一个线程在访问一个锁对象之前,该锁对象没有被其他线程访问过,那么该线程就可以获得该锁,并把MarkWord中的偏向锁标识符设置为该线程的唯一标识符。这样,如果以后再有该线程访问该锁对象,那么该线程就可以直接获取锁,而不再需要竞争。如果其他线程要访问该锁对象,则会先调用CAS操作来检测当前锁标识符是否等于线程的唯一标识符,如果是,则获取锁成功,否则锁标识符被升级为轻量级锁。

例如:

public class Test {
    public static void main(String[] args) {
        synchronized (Test.class) {
            synchronized (Test.class) {
                System.out.println("Nested Lock!");
            }
        }
    }
}

在上述代码中,当线程A第一次执行synchronized块时,会尝试获取Test.class的锁并将该锁的状态设置为 ''Locked",然后线程A对应的锁标识符会被设置为A的特定标识符。当线程A第二次执行synchronized块时,会检测Test.class的锁标识符是否等于线程A的特定标识符,如果等于,则获取锁成功,否则尝试CAS操作将该锁的状态从 ''Unlocked" 修改为 ''Locked";如果修改成功,则锁标识符被设置为A的特定标识符,获取锁成功,否则线程A会将该锁升级为轻量级锁。

综述: 以上就是Java synchronized的底层实现原理以及锁优化的攻略,通过深入了解synchronized关键字的底层实现原理以及锁的优化机制,可以使我们在程序开发过程中更加高效地使用多线程技术,提高程序的性能。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java synchronized底层实现原理以及锁优化 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • Java获取上月份最后一天日期8位的示例代码

    下面是Java获取上月份最后一天日期8位的示例代码攻略: 一、获取上月份最后一天的日期 一般情况下,获取任意月份的最后一天日期的代码如下: Calendar calendar = Calendar.getInstance(); // 将日期设置为当月的1号 calendar.set(Calendar.DATE, 1); // 月份-1,即可得到上个月的时间 …

    Java 2023年5月20日
    00
  • Java将时间按月份分段的实现思路与方法

    下面我将为您详细介绍Java将时间按月份分段的实现思路与方法,包含以下几个部分: 分析需求 算法思路 代码实现 示例验证 1. 分析需求 我们需要实现一个方法,将给定的时间段按照月份进行划分,每个月份的范围为起始日到月底的最后一天。 例如,时间段为2022年2月1日到2022年4月30日,则按月份分段后为: 2022年2月1日 ~ 2022年2月28日 20…

    Java 2023年5月20日
    00
  • Java过滤器与监听器间区别与联系

    Java过滤器与监听器的区别和联系 本文主要讲解Java Web中过滤器和监听器的区别和联系。过滤器(Filter)和监听器(Listener)都可以通过Web.xml进行配置,并且也可以通过注解的方式进行配置。 过滤器(Filter) 过滤器是在请求被处理之前对http请求和response进行预处理的技术,它可以拦截客户端发送的请求和服务器返回的响应,同…

    Java 2023年6月15日
    00
  • Tomcat配置及如何在Eclipse中启动

    下面我将详细讲解Tomcat配置及如何在Eclipse中启动的完整攻略。 1. Tomcat配置 Tomcat是开源的Web应用程序服务器,它可以为使用Java Servlet和JSP的Web应用程序提供运行环境。在使用Tomcat之前,需要进行配置。 1.1 下载Tomcat 首先需要在Tomcat官网下载Tomcat安装包,下载地址为http://tom…

    Java 2023年5月19日
    00
  • Spring MVC Annotation验证的方法

    对于Spring MVC Annotation验证的方法,我们需要做如下几个步骤: 1.导入相关依赖包 首先,我们需要在项目中导入相关的依赖包,以支持Spring MVC的注解验证。主要的依赖包如下: <dependency> <groupId>org.springframework</groupId> <artif…

    Java 2023年6月15日
    00
  • java文件的简单读写操作方法实例分析

    Java文件的简单读写操作方法实例分析 在 Java 程序开发中,我们经常需要对文件进行读写操作。本篇攻略将详细介绍 Java 文件读写的方法以及相关注意事项。 文件读取操作 在 Java 中,我们可以使用 FileInputStream 和 BufferedInputStream 类来读取文件。 FileInputStream import java.io…

    Java 2023年5月20日
    00
  • java 如何判断是否是26个英文字母

    要判断一个字符是否为26个英文字母中的一个,Java中可以使用Character类提供的isLetter()方法进行判断。isLetter()方法判断一个字符是否为字母,其定义如下: public static boolean isLetter(char ch) 该方法接受一个字符参数ch,并返回一个boolean类型的值表示该字符是否为字母。 示例1:使用…

    Java 2023年5月27日
    00
  • java中日期格式化的大坑

    关于“java中日期格式化的大坑”,我会从以下几个方面进行讲解: Java中日期格式化的基本知识 Java中日期格式化的坑点 解决Java中日期格式化的坑点的方法 两个示例来说明日期格式化的坑点 Java中日期格式化的基本知识 在Java中,要进行日期格式化,需要用到SimpleDateFormat类。该类是线程不安全的类,一般情况下,建议使用ThreadL…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部