Java synchronized底层的实现原理

Java中的synchronized关键字是一种用来控制多线程同时访问共享资源的机制,通过synchronized关键字的应用可以保证同一时刻只有一个线程执行某个方法或代码块。

synchronized的锁定对象可以是普通对象,但需要注意的是,synchronized作用在对象上时,不同的对象之间互不影响,一个对象的锁与另一个对象的锁是互相独立的。下面来详细讲解Java synchronized底层的实现原理。

1. synchronized 实现原理

synchronized 的实现原理主要通过对象头(Mark Word)的结构来完成。

在JVM中,对象在Heap区域中分配,它所具有的内存结构中,有一个叫做"对象头"(Mark Word)的区域,这个区域用2个字节(16bit)的存储空间来表示锁。

每个对象都有一个ID(lock ID)和自旋次数(spin times)。JVM中的线程在尝试获得锁的时候,会更新这个对象头的lock ID和自旋次数。当线程成功获得锁时,这个锁的ID会变为线程的ID,同时,自旋计数器也会被清零。当一个线程尝试获得锁失败时,就会进入等待状态。

在Java 6之前,synchronized锁只有一种形式,也就是重量级锁,这种同步锁在JVM内部使用操作系统线程互斥量(Mutex)来实现。在JVM内部,Java对象头中有一个锁标志位,它表示这个对象是被哪个线程锁定的,如果没有线程锁定它,就表示这个对象没有被锁定。

在Java 6之后,引入了锁升级和轻量级锁的机制,可以高效的控制锁的获取和解除,从而提高程序的并发性能。

2. synchronized 的锁优化

2.1 锁升级

在JVM中,锁除了重量级锁和轻量级锁之外,还有一种适应性自旋锁。这种锁会在未竞争时自旋获取锁,如果自旋的时间过长或者自旋的次数达到了一定的值,就会升级为重量级锁。

锁升级的优点在于可以高效的控制锁的获取和解除,从而提高程序的并发性能。

2.2 锁消除

在代码编写过程中,如果发现某些代码块不会被多个线程同时访问,就可以使用锁消除的机制,将锁消除掉,从而达到优化的效果。

3. 示例说明

3.1 示例一:synchronized 语句块

下面是一个使用synchronized关键字的简单示例代码,代码中使用了synchronized语句块,来保证对共享资源的操作是线程安全的。

public class SynchronizedExample {
    private int count = 0;
    private Object lock = new Object();

    public void increment() {
        synchronized (lock) {
            count++;
        }
    }

    public int getCount() {
        return count;
    }
}

在这个示例代码中,节点lock就是锁定的对象。当某一个线程想要访问increment()方法时,如果这个方法已经被另一个线程锁定了(也就是lock已经被锁定了),那么这个线程就会进入等待状态,直到锁被释放。

3.2 示例二:volatile 与 synchronized 的区别

下面是一个使用volatile关键字的示例代码,代码中使用了volatile关键字,来保证对共享资源的操作是线程安全的。

public class VolatileExample {
    private volatile int count = 0;

    public void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

在这个示例代码中,使用volatile关键字来修饰count变量,将其声明为volatile型变量。由于volatile变量的特性,保证了它的可见性和禁止指令重排序的效果,从而保证了多线程下的安全访问。

然而,上述代码仅仅保证了volatile变量的原子性,而没有保证整个increment()方法的原子性,也就是说,如果多个线程同时访问increment()方法,就有可能造成线程安全问题。

相比之下,使用synchronized关键字能够保证整个代码块的原子性,不会出现线程安全问题。但是,synchronized关键字会在进入和退出同步块时,执行一些额外的操作,从而降低了程序的性能。

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

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

相关文章

  • Spring MVC项目开发踩过的一些bug

    下面是详细的攻略: Spring MVC项目开发踩过的一些bug 1. 关于jsp页面中的EL表达式 在jsp页面中使用EL表达式时,在表达式中不要包含两对#{和},如果要包含两对,则需要使用反斜线进行转义。例如:在表单中使用<input type=”text” name=”username” value=”${user.name}”>,表示把u…

    Java 2023年6月15日
    00
  • Spring Boot日志控制详解

    Spring Boot日志控制详解 简介 在应用程序中,日志是非常重要的组成部分。通过日志,我们可以了解应用程序中所发生的事件及其执行状态。Spring Boot提供了非常方便的日志控制功能,使得应用程序中的日志记录变得更加简单、可读且易于管理。 Spring Boot默认日志记录器 Spring Boot默认使用的是Logback日志框架,它拥有极高的性能…

    Java 2023年6月1日
    00
  • springboot+idea+maven 多模块项目搭建的详细过程(连接数据库进行测试)

    下面详细讲解一下如何使用Spring Boot、IDEA和Maven搭建多模块项目并连接数据库测试。 环境准备 在开始之前,确保你已经安装了以下环境: JDK 1.8或以上版本 IDEA集成开发环境 Maven构建工具 数据库(本次示例使用MySQL) 创建Maven多模块项目 打开IDEA,点击File -> New -> Project,选择…

    Java 2023年5月31日
    00
  • 详解Java-Jackson使用

    详解Java-Jackson使用 简介 Jackson是一个流行的Java库,用于序列化和反序列化Java对象和JSON数据。它提供了快速,灵活,易于使用的API。 本文将详细讲解在Java项目中如何使用Jackson进行序列化和反序列化,包括几个常用的场景和示例。 添加依赖 要使用Jackson,在Java项目中需要添加Jackson的依赖。可以通过在Ma…

    Java 2023年5月19日
    00
  • JAVA面试题String产生了几个对象

    对于这道Java面试题,我们先来分析一下。 在Java中,String是一个不可变的对象,也就是说一旦创建了一个String对象,它就不能被修改。同时,Java也为了提高程序的运行效率,在处理String对象时使用了String Pool技术。简单来讲,就是Java会尝试复用已经存在的String对象,而不是在每次需要创建新对象时都新建一个对象,这种技术可以…

    Java 2023年5月26日
    00
  • 详解Struts2拦截器机制

    详解Struts2拦截器机制 1. 什么是Struts2拦截器 Struts2拦截器是一个非常重要的组件,用于对请求进行拦截和处理,同时也是整个Struts2框架的核心。 在Struts2中,每个请求都会经过多个拦截器的处理,每个拦截器只是完成了部分工作,多个拦截器组合在一起,最终完成了一个完整的请求处理流程。 2. Struts2拦截器机制的流程 Stru…

    Java 2023年5月20日
    00
  • java计算代码段执行时间的详细代码

    下面我来详细讲解一下Java计算代码段执行时间的流程和代码。 问题背景 在开发过程中,我们常常需要测试代码的执行时间,以便优化和改进代码的性能。例如,我们需要知道某段代码的运行时间,以便在性能敏感的应用中进行优化,或者判断代码是否需要并行化等。 解决方案 Java提供了System.currentTimeMillis()方法和System.nanoTime(…

    Java 2023年5月20日
    00
  • tomcat共享多个web应用会话的实现方法

    实现多个Web应用共享会话的方法有很多,而在Tomcat中,也存在不同的实现方式。下面将详细讲解几种可行的方案。 方案一:使用Tomcat的内置共享会话功能 Tomcat自身具备相应的共享会话功能,可以通过修改配置文件来启用该功能。首先,在Tomcat安装目录下找到conf/context.xml文件,在其中添加以下配置: <Valve classNa…

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