通过实例解析JMM和Volatile底层原理

通过实例解析JMM和Volatile底层原理

JMM的概念和作用

Java内存模型(JMM)是Java运行时的一部分,它定义了Java程序在多线程环境下内存的访问方式。JMM的主要目的是确保在多线程环境下,不同线程之间对共享数据的操作是有序、可见、原子的。

JMM通过以下方式实现这些目标:

  • 确保线程之间的可见性:JMM保证一个线程对共享变量的修改,对后续对该变量的读取是可见的。
  • 确保操作的原子性:JMM保证每次读写操作都是原子的,即不会被线程中断。
  • 确保操作的有序性:JMM保证程序执行时,不会出现指令重排序的情况,以保证操作的有序性。

Volatile关键字的使用

在多线程编程中,Volatile是一个非常重要的关键字。它可以保证变量在多个线程之间的可见性,同时也可以防止指令重排序,从而保证操作的有序性。

当一个变量被声明为Volatile,它会被存储到主内存中,并且每个线程都会从主内存中获取最新的值。这样,在一个线程修改变量值后,其他线程会立即看到最新值。

以下是一个示例,展示了Volatile关键字的使用:

public class VolatileTest {
    private volatile boolean flag = false;

    public static void main(String[] args) {
        VolatileTest test = new VolatileTest();
        new Thread(() -> {
            int i = 0;
            while (!test.flag) {
                i++;
            }
            System.out.println("Thread1 finished. i = " + i);
        }).start();

        new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            test.flag = true;
            System.out.println("Thread2 finished.");
        }).start();
    }
}

在上面的示例中,我们创建了一个Volatile关键字修饰的变量flag,并在两个线程中使用这个变量。其中,线程1会一直循环,直到变量flag被修改为true。而线程2会在一秒钟后,将变量flag修改为true。由于flag是Volatile类型的变量,线程1能够立即看到这个变量的最新值,从而结束循环并输出结果。

JMM底层原理示例

在JVM中,代码执行是由一个线程池来管理的。每个线程都会被分配一个本地线程栈,用来保存线程执行的方法和局部变量等信息。

在多线程环境下,每个线程都有自己的本地线程栈和程序计数器。这就意味着,每个线程都有自己的一套执行状态,包括执行顺序、程序计数器、寄存器等等。

为了保证多线程之间的可见性,多个线程需要使用共享内存进行通信。共享内存区域被称为主内存,在JMM中,主内存是所有线程共享的内存。

每个线程还有自己的工作内存,工作内存中保存了对共享变量的副本。线程对共享变量的操作都是在工作内存中完成的,而不是直接在主内存中操作。当线程需要对共享变量进行操作时,它会先将变量从主内存中复制到工作内存中,然后进行操作。操作完成后,线程再将结果刷新到主内存中,使其对其他线程可见。

以下是一个双重检查锁定的示例,展示了JMM的底层原理:

public class Singleton {
    private volatile static Singleton instance;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

在上面的示例中,我们创建了一个单例类Singleton,在getInstance方法中,我们使用了双重检查锁定的方式来保证类的唯一实例。其中,关键字Volatile被用来保证线程能够立即看到instance变量的最新值,确保多线程下正常工作。同时,在双重检查锁定的代码块中,我们使用了synchronized关键字来确保代码块同时只能被一个线程执行,从而保证线程安全。

总结

本文通过实例,详细讲解了JMM和Volatile的底层原理。了解这些概念和原理,可以帮助我们更好地理解Java多线程编程,更加高效地解决多线程环境下的安全问题。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:通过实例解析JMM和Volatile底层原理 - Python技术站

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

相关文章

  • 如何为Redis中list中的项设置过期时间

    Redis是一个伟大的工具,用来在内存中存储列表是很合适的。 不过,如果你想要快速搜索列表,同时需要让列表中每项都在一定时间后过期,应该怎么做呢? 首先,当然不能使用不同的类似的key存储数据,然后使用keys命令来获取所有类似key的数据。这样的开销是不可接受的。 Redis并没有直接提供方法做这件事,但是这是可以做到的!虽然最后用的未必是Redis的Li…

    Redis 2023年4月11日
    00
  • Oracle、MySQL和SqlServe三种数据库分页查询语句的区别介绍

    关于Oracle、MySQL、SQL Server三种数据库分页查询语句的区别介绍如下: 1. Oracle分页查询语句 在Oracle数据库中,分页查询需要使用ROWNUM和子查询来实现。具体的查询语句如下: SELECT * FROM ( SELECT ROWNUM AS RN, T.* FROM ( SELECT * FROM table_name O…

    database 2023年5月21日
    00
  • MySQL事务与锁实例教程详解

    MySQL事务与锁实例教程详解 什么是MySQL事务? MySQL事务是指一系列的对数据库进行读写的操作,这些操作被视为一个整体并被立即一起提交或回滚。一个完整的事务必须满足四个属性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)(也称为ACID特性)。- 原子性:事务的所有操作都…

    database 2023年5月21日
    00
  • Python 基于Python从mysql表读取千万数据实践

    基于Python 从mysql表读取千万数据实践   by:授客 QQ:1033553122 场景:   有以下两个表,两者都有一个表字段,名为waybill_no,我们需要从tl_waybill_bar_record表读取1000w条唯一的waybill_no,然后作为INSERT SQL语句的一部分,填充到ts_order_waybill的waybill…

    MySQL 2023年4月13日
    00
  • MySQL Shell的介绍以及安装

    MySQL Shell是MySQL官方推出的一款交互式的Shell工具,可以通过命令行或者脚本方式来管理和操作MySQL数据库。下面将介绍MySQL Shell的安装方法以及其基本操作。 安装MySQL Shell MySQL Shell支持在Windows、Mac OS、Linux等多种操作系统上运行,我们可以从MySQL官网下载适合我们系统的版本,然后进…

    database 2023年5月18日
    00
  • MySQL如何分析查询语句?

    MySQL是一种开源的、用于管理关系型数据库的软件,它支持许多不同的数据类型和适用于各种应用程序的查询语句。因此,在对MySQL上运行的查询进行优化和调整时,它可以提供一些有用的工具以确保查询能够更快速和有效地执行。 MySQL可以分析查询语句,以便在查询之前确定最佳的查询计划。查询计划是指MySQL如何检索数据并将它们返回给用户的过程。MySQL通过分析查…

    MySQL 2023年3月10日
    00
  • oracle复制表结构和复制表数据语句分享

    下面是oracle复制表结构和复制表数据语句分享的完整攻略: 复制表结构 1.使用CREATE TABLE AS SELECT语句 CREATE TABLE new_table AS SELECT * FROM old_table WHERE 1=2; 以上SQL语句将复制old_table的表结构到new_table中。其中,WHERE子句中的1=2表示不…

    database 2023年5月21日
    00
  • Entity Framework Core中执行SQL语句和存储过程的方法介绍

    当我们使用Entity Framework Core时,我们通常会使用查询编写LINQ查询,这对于大多数业务场景来说已经足够了。但是,某些情况下,我们可能需要执行原始SQL查询或调用存储过程。本文将介绍在Entity Framework Core中执行SQL语句和存储过程的方法。 执行SQL查询 在Entity Framework Core中,我们可以使用F…

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