java自旋锁和JVM对锁的优化详解

yizhihongxing

Java自旋锁和JVM对锁的优化详解

在多线程并发编程中,锁的使用尤为重要。Java中的锁主要包括synchronized关键字和ReentrantLock类,这些锁在实现上都涉及到了自旋锁和JVM对锁的优化。

什么是自旋锁

自旋锁是指当一个线程获得锁后,发现其他线程正在使用该锁,则该线程不会立即阻塞,而是一直循环等待直到其他线程释放该锁。

在Java中,synchronized关键字就是一种典型的自旋锁。当一个线程进入synchronized代码块时,如果发现锁已经被其他线程占用,则该线程会不断自旋等待直到获取到锁。

在单核处理器上,自旋锁的效率是比较高的,因为线程的上下文切换是比较耗时的。但在多核处理器上,自旋锁的效率会降低,因为自旋的线程会竞争CPU资源,导致CPU利用率降低。

JVM对锁的优化

JVM在实现锁时,有一些优化策略可以提高线程的并发能力。

偏向锁

偏向锁是指当一个线程第一次进入同步块时,JVM会将锁定对象头记录下来,并将线程ID记录到锁对象中,表示该线程已经获得了锁。

当这个线程再次进入同步块时,JVM会检查锁定对象头中记录的线程ID是否是当前线程。如果是,则表示该线程仍然持有锁,就可以直接进入同步块执行代码。如果不是,则需要撤销偏向锁,升级为轻量级锁。

偏向锁的优势在于减少了锁的竞争,提高了同步代码的执行效率。

轻量级锁

轻量级锁是指当两个线程同时进入同步块时,JVM会先将锁的对象头记录下来,并将对象头中的标志位设置为“轻量级锁”。然后,JVM会将锁定对象的Mark Word复制一份到线程的栈帧中,以便线程在解锁时恢复锁定对象的状态。

当第二个线程进入同步块时,JVM会继续检查锁的对象头中的标志位,并比较线程栈帧中的锁对象是否与Mark Word一致。如果一致,则表示当前线程持有锁,可以直接执行同步块的代码。如果不一致,则需要撤销轻量级锁,升级为重量级锁。

重量级锁

重量级锁是指当多个线程竞争同步块时,JVM会把它们全部阻塞,并将它们对锁的访问转为内核级别的操作。这时,CPU会从用户态切换到内核态,导致用户线程的阻塞和解阻塞都需要切换状态,造成较大的系统开销。

重量级锁的优势在于不会消耗CPU资源,因为线程会被阻塞,不会自旋等待。

自旋锁和JVM优化的示例

示例1:偏向锁

public class BiasedLockExample {
    private static Object object = new Object();

    public static void main(String[] args) throws InterruptedException {
        synchronized (object) {
            Thread.sleep(5000); // 睡眠5秒钟,模拟该线程正在占用锁
            System.out.println("当前线程:" + Thread.currentThread().getId());
        }
    }
}

在代码中,我们使用synchronized锁定了一个对象,并在同步块中睡眠了5秒钟,模拟该线程正在占用锁。

然后,我们启动两个线程,其中一个线程首先获取到了锁,然后打印当前线程的ID。另外一个线程在获取锁时,因为该锁已经被偏向了第一个线程,所以直接进入了同步块,输出了第一个线程的ID。

输出结果如下:

当前线程:1
当前线程:1

从结果中可以看出,第二个线程直接获得了锁,并没有阻塞。

示例2:轻量级锁

public class LightLockExample {
    private static Object object = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            synchronized (object) {
                try {
                    Thread.sleep(5000); // 睡眠5秒钟,模拟该线程正在占用锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程1正在执行");
            }
        });
        Thread t2 = new Thread(() -> {
            synchronized (object) {
                System.out.println("线程2正在执行");
            }
        });

        t1.start();
        Thread.sleep(1000); // 等待线程1先获取到锁
        t2.start();
    }
}

在代码中,我们启动两个线程,其中第一个线程获取到了锁后,又睡眠了5秒钟,模拟该线程正在占用锁。

然后,我们启动第二个线程,该线程尝试获取锁,由于锁已经被第一个线程获取了,因此该线程会进入自旋等待。

等第一个线程结束后,第二个线程才能获取到锁,并输出“线程2正在执行”信息。

输出结果如下:

线程1正在执行
线程2正在执行

从结果中可以看出,第二个线程在获取锁时,没有直接进入同步块,而是进入了自旋等待状态。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java自旋锁和JVM对锁的优化详解 - Python技术站

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

相关文章

  • 十种JAVA排序算法实例

    十种JAVA排序算法实例攻略 一、排序算法简介 排序算法是指将一组无序的数据按照一定的顺序重新排列的过程。在计算机领域中,排序算法是最基本的算法之一,大大提高了计算机数据处理的效率。 排序算法的分类可以分为内部排序和外部排序。内部排序是指数据量较小,能全部加载进内存中进行排序的方法,比如插入排序、冒泡排序等。而外部排序是指数据量较大,需要借助外部存储设备进行…

    Java 2023年5月19日
    00
  • Spring RedirectAttributes参数跳转代码实例

    Spring中RedirectAttributes参数跳转是一个基于重定向的方案。它把需要传递的参数放在URL中或放在Session中,然后传递到下一个控制器中,达到了控制器之间的传值与跳转。跳转时可以使用内置默认的redirect:或forward:前缀,或者使用URL绝对路径或相对路径来进行跳转。 下面是具体实现步骤。 1. 添加依赖 在项目中的pom.…

    Java 2023年6月15日
    00
  • 微信小程序扫描二维码获取信息实例详解

    微信小程序扫描二维码获取信息实例详解 背景 随着移动互联网的普及和快速发展,微信小程序已经成为了人们日常生活中必不可少的一部分。其中一项最常见的功能是扫描二维码获取信息。本文将详细讲解微信小程序扫描二维码获取信息的实现过程,包括如何生成二维码并在小程序中读取二维码信息。 生成二维码 在微信小程序中生成二维码有很多方法,可以使用第三方库,也可以使用微信提供的A…

    Java 2023年5月23日
    00
  • springboot整合JSR303参数校验与全局异常处理的方法

    下面我将详细讲解“springboot整合JSR303参数校验与全局异常处理的方法”的完整攻略。 一、JSR303参数校验 JSR303,又称Bean Validation,是一个JavaEE标准的框架,可以很方便地对JavaBean的字段进行校验,以保证数据的有效性和安全性。在springboot中,我们可以通过集成hibernate-validator来…

    Java 2023年5月19日
    00
  • Java实现监控多个线程状态的简单实例

    下面是Java实现监控多个线程状态的简单实例的完整攻略。 监控线程状态概述 Java中提供了一些API可以用来监控线程的状态。线程状态通常包括:NEW(新生)、RUNNABLE(运行)、BLOCKED(阻塞)、WAITING(等待)、TIMED_WAITING(定时等待)和TERMINATED(终止)。 实现步骤 下面是Java实现监控多个线程状态的简单实例…

    Java 2023年5月18日
    00
  • java web项目Session获取不到问题及解决

    我们来详细讲解一下“Java Web项目Session获取不到问题及解决”的攻略。 问题的描述 在 Java Web 项目中,我们经常使用 Session 来进行用户状态的维护和管理。但有时我们会发现,无法获取到已经创建的 Session,这样就会导致用户登录等功能出现问题。 问题的原因 造成 Session 获取失败的原因有很多,具体包括以下几个方面: 代…

    Java 2023年6月15日
    00
  • 浅析java异常栈

    下面我将为您详细讲解“浅析Java异常栈”的完整攻略。 浅析Java异常栈 异常栈的概述 在Java中,异常是指当前程序不能够继续执行下去的错误或问题。当程序发生异常时,会自动创建一个异常对象,并将这个异常对象抛出给Java虚拟机,Java虚拟机再根据异常对象调用相应的异常处理程序进行处理。 异常栈是异常处理机制的重要组成部分,它是一个由多个异常堆栈组成的数…

    Java 2023年5月27日
    00
  • Spring Data JPA实现数据持久化过程详解

    Spring Data JPA实现数据持久化过程详解 什么是Spring Data JPA Spring Data JPA是Spring框架下的一个模块,它提供了一种方便、基于注解的方式来实现JPA的操作,将JPA的复杂性隐藏在背后。Spring Data JPA是JPA操作的一个高层封装,使数据与业务分离,可以快速的开发出高质量的数据访问层。 Spring…

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